有许多问题以一种或另一种方式提出:“在呈现视图的某些部分后,我该如何做某事?” (这里、这里和这里只是给出一些)。答案通常是:
- 用于在最初呈现
didInsertElement
视图时运行代码。 - 如果您需要访问已创建的 DOM 元素,则用于在刷新视图更改后运行
Ember.run.next(...)
您的代码。 - 在加载所需的数据后,使用观察者
isLoaded
或类似的属性来做某事。
令人恼火的是,它会导致一些看起来非常笨拙的事情:
didInsertElement: function(){
content.on('didLoad', function(){
Ember.run.next(function(){
// now finally do my stuff
});
});
}
当您使用 ember-data 时,这甚至不一定有效,因为isLoaded
可能已经是真的(如果之前已经加载了记录并且没有再次从服务器请求)。所以要正确排序是很困难的。
最重要的是,您可能已经在您的视图模板中观看 isLoaded,如下所示:
{{#if content.isLoaded}}
<input type="text" id="myTypeahead" data-provide="typeahead">
{{else}}
<div>Loading data...</div>
{{/if}}
并在您的控制器中再次执行此操作似乎是重复的。
我想出了一个稍微新颖的解决方案,但它要么需要工作,要么实际上是个坏主意……这两种情况都可能是真的:
我编写了一个名为 Handlebars 的小助手{{fire}}
,它会在执行包含的把手模板时触发一个具有自定义名称的事件(即,每次重新渲染子视图时都应该这样做,对吧?)。
这是我很早的尝试:
Ember.Handlebars.registerHelper('fire', function (evtName, options) {
if (typeof this[evtName] == 'function') {
var context = this;
Ember.run.next(function () {
context[evtName].apply(context, options);
});
}
});
像这样使用:
{{#if content.isLoaded}}
{{fire typeaheadHostDidRender}}
<input type="text" id="myTypeahead" data-provide="typeahead">
{{else}}
<div>Loading data...</div>
{{/if}}
这基本上可以按原样工作,但它有几个我已经知道的缺陷:
- 它调用控制器上的方法......至少能够将“事件”发送到祖先视图对象可能会更好,甚至可能使其成为默认行为。我试过
{{fire typeaheadHostDidRender target="view"}}
了,但没有用。我还看不到如何从传递给助手的内容中获取“当前”视图,但显然{{view}}
助手可以做到。 - 我猜有比我在这里做的更正式的方式来触发自定义事件,但我还没有学会。jQuery
.trigger()
似乎不适用于控制器对象,尽管它可能适用于视图。有没有“Ember”的方式来做到这一点? - 可能有些事情我不明白,例如会触发此事件但视图实际上不会添加到 DOM 的情况......?
正如您可能猜到的,我正在使用 Bootstrap 的 Typeahead 控件,并且我需要在<input>
渲染后连接它,这实际上只发生{{#if}}
在我的模板中的几个嵌套块评估为 true 之后。我也使用 jqPlot,所以我经常需要这种模式。这似乎是一个可行且有用的工具,但可能是我遗漏了一些使这种方法变得愚蠢的大图景。或者也许还有另一种方法没有出现在我的搜索中?
有人可以为我改进这种方法或告诉我为什么这是一个坏主意吗?
更新
我已经弄清楚了一些问题:
- 我可以通过 ...obvious 获得第一个“真实”包含视图
options.data.view.get('parentView')
,但我认为它不会那么简单。 - 您实际上可以
obj.trigger(evtName)
在任意对象上执行 jQuery 样式...但是该对象必须扩展Ember.Evented
mixin!所以我认为这是在 Ember 中发送这种事件的正确方法。只需确保预期的目标扩展Ember.Evented
(视图已经扩展)。
这是迄今为止的改进版本:
Ember.Handlebars.registerHelper('fire', function (evtName, options) {
var view = options.data.view;
if (view.get('parentView')) view = view.get('parentView');
var context = this;
var target = null;
if (typeof view[evtName] == 'function') {
target = view;
} else if (typeof context[evtName] == 'function') {
target = context;
} else if (view.get('controller') && typeof view.get('controller')[evtName] == 'function') {
target = view.get('controller');
}
if (target) {
Ember.run.next(function () {
target.trigger(evtName);
});
}
});
现在我所缺少的只是弄清楚如何传入预期的目标(例如控制器或视图——上面的代码试图猜测)。或者,找出是否存在破坏整个概念的意外行为。
还有其他输入吗?