web-dev-qa-db-fra.com

Accéder au magasin à partir du composant

j'ai un composant et lorsque l'utilisateur clique sur le composant, il ajoute une valeur à stocker, j'essaie d'utiliser de cette façon mais j'obtiens une erreur:

OlapApp.MeasureListItemComponent = Ember.Component.extend({
  tagName: 'li',
  isDisabled: false,
  attributeBindings: ['isDisabled:disabled'],
  classBindings: ['isDisabled:MeasureListItemDisabled'],

  actions: {
    add: function(measure) {
      var store = this.get('store');
      store.Push('OlapApp.AxisModel', {
            uniqueName: measure.uniqueName,
            name: measure.name,
            hierarchyUniqueName: measure.hierarchyUniqueName,
            type: 'row',
            isMeasure: true,
            orderId: 1
      });
    }
  }
});

et c'est une erreur:

Uncaught TypeError: Cannot call method 'Push' of undefined  MeasureListItemComponent.js:18

est-il possible de pousser l'enregistrement pour le stocker à partir du composant? pourquoi je ne peux pas accéder au magasin? mon nom de modèle est "AxisModel" et l'espace de noms de l'application est "OlapApp"

49
MBehtemam

Dans un component le magasin n'est pas injecté automatiquement comme dans les route ou controller au démarrage de votre application. En effet, les composants sont considérés comme plus isolés.

Ce qui suit ci-dessous n'est pas considéré comme une meilleure pratique. Un composant doit utiliser les données qui lui sont transmises et ne pas connaître son environnement. La meilleure façon de gérer ce cas serait d'utiliser sendAction pour développer ce que vous voulez faire et de gérer l'action avec store dans le contrôleur lui-même.

@ sly7_7 est une bonne suggestion, et si vous avez beaucoup de composants d'où vous avez besoin d'accéder au magasin, alors ce pourrait être un bon moyen de le faire.

Une autre approche pour accéder à votre store pourrait être d'obtenir la référence de store à votre component entourant controller. Dans ce cas, peu importe quel controller c'est parce que chaque controller a déjà une référence au store injecté dedans. Alors maintenant, pour arriver à votre store pourrait être fait en obtenant le component's targetObject qui sera le controller entourant le component puis récupérez le store.

Exemple:

OlapApp.MeasureListItemComponent = Ember.Component.extend({
  ...
  actions: {
    add: function(measure) {
      var store = this.get('targetObject.store');
      ...
    }
  }
});

Voir ici pour un exemple de travail.

J'espère que ça aide.

Mettre à jour en réponse à votre commentaire ayant des composants imbriqués

Si, par exemple, votre composant enfant n'est imbriqué que d'un niveau, vous pouvez toujours vous référer à targetObject du parent en utilisant parentView:

App.ChildCompComponent = Ember.Component.extend({
  storeName: '',
  didInsertElement: function() {
    console.log(this.get('parentView.targetObject.store'));
    this.set('storeName', this.get('parentView.targetObject.store'));
  }
});

Mise à jour exemple .

43
intuitivepixel

Depuis Ember v1.10, le magasin peut être injecté aux composants à l'aide d'initialiseurs, voir: http://emberjs.com/blog/2015/02/07/ember-1 -10-0-release.html # toc_injected-properties :

export default Ember.Component.extend({
    store: Ember.inject.service()
});
44
Jacob van Lingen

Depuis Ember 2.1.0

export default Ember.Component.extend({
  store: Ember.inject.service('store'),
});

avant Ember 2.1.0 - voie d'injection de dépendance

App.MyComponent = Ember.Component.extend({

  store: Ember.computed(function() {
     return this.get('container').lookup('store:main');
  })

});

avant Ember 2.1.0 - chemin du contrôleur

Vous pouvez transmettre le magasin en tant que propriété à partir du contrôleur:

App.MyComponent = Ember.Component.extend({

  value: null,
  store: null,
  tagName: "input",

  didInsertElement: function () {

     if (!this.get('store')) {
        throw 'MyComponent requires store for autocomplete feature. Inject as store=store'
     }
  }

});

Le magasin est disponible sur chaque contrôleur. Ainsi, dans la vue parent, vous pouvez inclure le composant comme suit:

{{view App.MyComponent
    store=store
    class="some-class"
    elementId="some-id"
    valueBinding="someValue"
}}

La transmission des propriétés au composant est documentée ici

14
Jan Míšek

La façon actuelle de faire cela avec ember-cli semble être avec un initialiseur. Très similaire à la réponse @ Sly7_7.

Pour obtenir un modèle de base, utilisez:

  ember g initializer component-store-injector

Modifiez ensuite ceci pour:

// app/initializers/component-store-injector.js

export function initialize(container, application) {
  application.inject('component', 'store', 'store:main');
}

export default {
  name: 'component-store-injector',
  initialize: initialize
};

Je crois que cela ajoutera le magasin à tous les composants.

Volé à https://github.com/ember-cli/ember-cli-todos

13
jomofrodo

Je ne sais pas si les composants sont destinés à être utilisés de cette façon. Mais si vous le souhaitez, je pense que vous pouvez déclarer un initialiseur et injecter le magasin dans tous les composants.

Ember.onLoad('OlaApp', function(OlaApp) {
  OlapApp.initializer({
    name: 'injectStoreIntoComponents',
    before: 'registerComponents',
    initialize: function(container, application){
      container.register('store:main', App.Store);
      container.injection('component', 'store', 'store:main');
    }
  })
});

Voici un exemple artificiel mais fonctionnel: http://jsbin.com/AlIyUDo/6/edit

7
sly7_7

Le magasin peut être injecté à l'aide d'une injection de dépendance.

Exemple

import Ember from 'ember';

export default Ember.Component.extend({

  /**
   *
   */
  store: Ember.inject.service(),

  /**
   * Initialize the component.
   */
  init() {
    this.initialize();

    this._super();
  },

  /**
   * Initialize the properties and prerequisites.
   */
  initialize() {
    // Set the component properties
    this.todos().then((data) => {
      this.set('todoEntries', data);
    });
  },

  /**
   * Returns the todo entries.
   *
   * @returns {*|Promise|Promise.<T>}
   */
  todos() {
    const store = this.get('store');

    return store.findAll('todo');
  },

});
6
user634545

Une autre façon que personne n'a encore mentionnée est de simplement passer controller.store au composant, par ex.

{{my-awesome-component store=controller.store}}
4
TrevTheDev