垃圾中可重复使用的物体的结构 [英] Architecture for reusable object in ember

查看:79
本文介绍了垃圾中可重复使用的物体的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ember构建管理信息板。我想创建一个可重用的图表对象,我可以在整个应用程序中拥有多个实例。图表对象应该包含一些模板,其中包含一些标记和一个canvas元素,在DOM中插入一个需要id的canvas元素,以便附加实际的图表(chart.js)。我尝试了几种方法,但我似乎无法想出正确的架构来做到这一点。



实现上述目标是正确的结构是什么? / p>

谢谢!

解决方案

Ember.Component 是你的朋友



由于@raulbrito已经提到过,如果您希望使用ember可重复使用的组件,最好的方式是使用新的 Ember.Component a href =http://www.w3.org/TR/2013/WD-components-intro-20130606/>新的w3网页组件草案,从而使未来证明。



我已经尝试了一个简单的例子来说明如何实现。
给出一个简单的路由其中模型钩子返回一些静态数据:



索引路线



  App.IndexRoute = Ember.Route.extend({
model :function(){
return Ember.Object.create({
modelOne:data,
modelTwo:data2
});
}
}) ;

数据 data2 是简单的全局定义的静态对象(您将在演示中看到 ,但这也可能是来自后台或固定装置等的数据。



索引模板



在模板中,我们使用行 {{line-chart data = model.modelOne}} 插入图表组件,如您所见,我们也设置数据属性到索引模型 model.modelOne model.modelTwo

 < script type =text / x-handlebarsid =index> 
< h2>图表1< / h2>
{{line-chart data = model.modelOne}}

< h2>图表二< / h2>
{{line-chart data = model.modelTwo}}
< / script>



组件模板



我们的组件模板看起来相当简单,因为它将呈现一个简单的 canvas 元素,但它可能会根据需要复杂,如何使用 Ember.Component 还请参阅文档

 < script type =text / x-handlebarsid =components / line-chart> 
< / script>



组件子类



 code> App.LineChartComponent = Ember.Component.extend({
tagName:'canvas',
attributeBindings:['width','height'],
width:'480 ',
height:'360',
data:null,
didInsertElement:function(){
var ctx = this.get('element')。getContext(2d );
var myNewChart = new Chart(ctx).Line(this.get('data'));
}
});

注意命名在这里很重要,Ember知道哪个子类基于其名称为组件提供功能。例如,如果您有一个名为 line-chart 的组件,您将创建一个名为 App.LineChartComponent 的子类。如果您的组件被称为 bar-chart-simple ,则类名称将为 App.BarChartSimpleComponent 等等。 Ember将使用组件的骆驼名称寻找一个类,其次是组件



所以, Ember.Component 从 Ember.View 扩展我们可以定义各种属性 Ember.View 支持像 tagName 。在我们的例子中,我们使用 canvas ,因为这是 chart.js 需要工作的。如您所见,我们还定义了一些 attributeBindings 来控制 width height C $ c> c $ c>从ember里面。该组件还定义了一个数据属性(可以调用任何你认为合适的),我们稍后在返回的模板中设置我们的模型数据来自 IndexRoute 模型钩子。最后在我们组件的 didInsertElement 钩子中,我们初始化图表传递与 this.get('data')数据对象新创建 Chart.js 类。

  var ctx = this.get( '元素')的getContext( 2D); 
var myNewChart = new Chart(ctx).Line(this.get('data'));

最后但并非最不重要的是,请看这里一个工作示例



希望有帮助。



对您最近的评论进行更新



我试图模拟模型的分辨率的延迟 hook来模仿后台的响应,你可以看到模板渲染正在等待模型承诺先解决。基本上我所做的是使用 Ember.run.later ,延迟2000ms,一旦超时就解决了承诺:

  App.IndexRoute = Ember.Route.extend({
model:function(){
return new Ember.RSVP.Promise(function ){
Ember.run.later(function(){
var m = Ember.Object.create({
modelOne:data,
modelTwo:data2
} );
resolve(m);
},2000);
});
}
});

只是为了好玩,我还添加了一个 LoadingRoute 在承诺解决方案正在等待数据时显示微调器, LoadingRoute 是一个较少记录的ember功能,您可以在这里阅读更多信息: https://gist.github.com/machty/5647589 我如何在(全球)加载微调一个转换是否承诺?



请参见这里更新一个例子: http://jsbin.com/odosoy/145/edit



更新以响应@ SamSelikoff的评论



至于上面提到的 LoadingRoute @SamSelikoff指出现在已经正式记录:http://emberjs.com/guides/routing/defining-your-routes/#toc_initial-routes


I am building an admin dashboard using ember. I want to create a reusable chart object of which I can have multiple instances throughout the application. The chart object should have a template consisting of some markup and a canvas element of which I need the id after insertion in the DOM in order to attach the actual chart (chart.js). I have tried several approaches, but I can not seem to figure out the right architecture to do this.

What would be the right architecture in ember to achieve the above?

Thanks!

解决方案

Ember.Component is your friend

As @raulbrito already mentioned, the best way to go if you want reusable components in ember is indeed to use the new Ember.Component which is heavily based on the new w3 draft for web components and thus beeing future proof.

I've tried to make a simple example on how this could be implemented. Given a simple route where the model hook returns some static data:

Index Route

App.IndexRoute = Ember.Route.extend({
  model: function(){
    return Ember.Object.create({
      modelOne: data,
      modelTwo: data2
    });
  }
});

data and data2 are simply static objects globally defined for simplicity (as you will see in the demo), but this could be also data coming from a backend or from fixtures etc.

Index template

In the template then we insert our chart component with the line {{line-chart data=model.modelOne}} and as you can see, we also set the data attribute to the index model model.modelOne or model.modelTwo:

<script type="text/x-handlebars" id="index">
  <h2>Chart one</h2>
  {{line-chart data=model.modelOne}}

  <h2>Chart two</h2>
  {{line-chart data=model.modelTwo}}
</script>

Component Template

Our component template looks fairly simple because it will render a simple canvas element, but it could be as complex as needed, on how to use Ember.Component please refer also to the docs:

<script type="text/x-handlebars" id="components/line-chart">
</script>

Component Subclass

App.LineChartComponent = Ember.Component.extend({
  tagName: 'canvas',
  attributeBindings: ['width', 'height'],
  width: '480',
  height: '360',
  data: null,
  didInsertElement: function() {
    var ctx = this.get('element').getContext("2d");
    var myNewChart = new Chart(ctx).Line(this.get('data'));
  }
});

Note the naming is important here, Ember knows which subclass powers a component based on its name. For example, if you have a component called line-chart, you would create a subclass called App.LineChartComponent. If your component was called bar-chart-simple, the class name would be App.BarChartSimpleComponent and so on. Ember will look for a class with the camelized name of the component, followed by Component.

So, and since Ember.Component extends from Ember.View we can define all sorts of properties Ember.View supports like tagName. In our case we use canvas because this is what chart.js needs to work. As you can see we have also defined some attributeBindings to control the width and height of the canvas from inside ember. The component has also a data attribute (which could be called whatever you find appropriate) defined on which we later set our model data in the template returned from the IndexRoute model hook. And finally in your didInsertElement hook of our component we initialize the chart passing with this.get('data') the data object to new created Chart.js class.

var ctx = this.get('element').getContext("2d");
var myNewChart = new Chart(ctx).Line(this.get('data'));

And last but not least, please see here for a working example of the above explained.

Hope it helps.

Update in response to your last comment

I've tried to simulate a delay in the resolution of the model hook to mimic a response from a backend, as you can see the template rendering is waiting for the model promise to resolve first. Basically what I've done is to use Ember.run.later with a delay of 2000ms that resolves the promise once timed out:

App.IndexRoute = Ember.Route.extend({
  model: function(){
    return new Ember.RSVP.Promise(function(resolve) {
      Ember.run.later(function() {
        var m = Ember.Object.create({
          modelOne: data,
          modelTwo: data2
        });
        resolve(m);
      }, 2000);
    });
  }
});

And just for fun I've also added a LoadingRoute to show a spinner while the promise resolution is waiting for data, the LoadingRoute is a less documented feature of ember, you can read more about it here: https://gist.github.com/machty/5647589 under How do I put up a (global) Loading Spinner during a transition w/ Promises?

Plase see here for a updated example: http://jsbin.com/odosoy/145/edit

Update in response to @SamSelikoff's comment

As for the above mentioned LoadingRoute @SamSelikoff pointed out that it's officially documented now: http://emberjs.com/guides/routing/defining-your-routes/#toc_initial-routes

这篇关于垃圾中可重复使用的物体的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆