Как вызвать метод компонента из контроллера
У меня есть компонент, представляющий карту, и после действия в моем контроллере я хочу вызвать метод для компонента, чтобы центрировать карту. Код выглядит следующим образом:
App.PlacesController = Ember.Controller.extend({
actions : {
centerMap : function () {
// how to call from here to GoogleMapComponent.centerMap ??
}
}
});
App.GoogleMapComponent = Ember.Component.extend({
centerMap : function () {
}
});
шаблон
{{google-map}}
<button {{action "centerMap"}}>Center Map</button>
Я нашел обходное решение, но я не думаю, что это способ Ember сделать это.
{{google-map viewName="mapView"}}
<button class="center-map">Center Map</button>
App.PlacesView = Ember.View.extend({
didInsertElement : function () {
this.$(".center-map").click(this.clickCenterMap.bind(this));
},
clickCenterMap : function () {
this.get("mapView").centerMap();
}
});
Ответы
Ответ 1
В Ember представления (Компоненты - это прославленные представления) знают о своем контроллере, но контроллеры НЕ знают о представлениях. Это по дизайну (MVC), чтобы держать вещи развязанными, и поэтому у вас может быть много видов, которые "питаются" от одного контроллера, а контроллер не является более мудрым. Поэтому, думая об отношениях, изменения могут произойти с контроллером, и представление будет реагировать на эти изменения. Поэтому, чтобы повторить, вы никогда не должны пытаться получить доступ к представлению/компоненту изнутри контроллера.
Есть несколько вариантов, о которых я могу думать при работе с вашим примером.
-
Сделайте кнопку частью своего компонента! Компоненты предназначены для обработки пользовательского ввода, например, нажатия кнопок, поэтому вы можете захотеть сделать кнопку частью компонента карты и обработать клики в хэш-настройках вашего компонента. Если эти кнопки всегда будут сопровождать компонент карты, я, безусловно, рекомендую этот подход.
-
У вас может быть логическое свойство на вашем контроллере, например isCentered
, и когда нажимается кнопка, устанавливается значение true. В вашем компоненте вы можете привязываться к этому свойству контроллера и реагировать при изменении этого свойства. Это двухсторонняя привязка, чтобы вы могли также изменить свой локально связанный объект на false, если пользователь перемещает карту, например.
Контроллер:
...
isCentered: false,
actions: {
centerMap: {
this.set('isCentered', true);
}
}
...
компонент:
...
isCenteredBinding: 'controller.isCentered',
onIsCenteredChange: function () {
//do your thing
}.observes('isCentered'),
...
-
Решение Джереми Грина может работать, если вы смешиваете в Ember.Evented mixin в контроллер (который добавляет методы pub/sub trigger
и on
)
Ответ 2
Вы можете использовать on
, чтобы ваш компонент прослушивал событие с контроллера, затем вы можете использовать trigger
в контроллере для испускания события.
Итак, в вашем компоненте у вас может быть что-то вроде этого:
didInsertElement : function(){
this.get('controller').on('recenter', $.proxy(this.recenter, this));
},
recenter : function(){
this.get("mapView").centerMap()
}
И в вашем контроллере вы могли бы:
actions : {
centerMap : function () {
this.trigger('recenter');
}
}
Ответ 3
Привязать свойство компонента к свойству контроллера в шаблоне:
{{google-map componentProperty=controllerProperty}}
Затем соблюдайте свойство компонента в компоненте:
onChange: function () {
// Do your thing
}.observes('componentProperty')
Теперь каждый раз, когда controllerProperty
изменяется в контроллере, будет вызываться onChange
в компоненте.
Из этого ответа, второй абзац.
Ответ 4
Я думаю, что это нормально, если у вас есть ссылка на ваш контроллер. Это правда, что ваш компонент инкапсулирует его собственное поведение, но общедоступные методы, такие как reload
и т.д., Отлично.
Мое решение для этого - передать текущему controller
компоненту и установить свойство на контроллере внутри компонента.
Пример
template.hbs:
{{#component delegate=controller property="refComponent"}}
component.js:
init: function() {
this._super.apply(this, arguments);
if (this.get("delegate")) {
this.get('delegate').set(this.get("property") || "default", this);
}
}
Теперь в вашем контроллере вы можете просто получить ссылку на свой компонент с помощью this.get("refComponent")
.
Штеффен
Ответ 5
Внутри вашего вызова компонента:
var parentController = this.get('targetObject');
Смотрите: http://emberjs.com/api/classes/Ember.Component.html#property_targetObject