Подтвердить что ты не робот

Как вызвать метод компонента из контроллера

У меня есть компонент, представляющий карту, и после действия в моем контроллере я хочу вызвать метод для компонента, чтобы центрировать карту. Код выглядит следующим образом:

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();
  }
});
4b9b3361

Ответ 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").

Штеффен