Доступ к хранилищу от компонента
У меня есть компонент, и когда пользователь нажимает на компонент, он добавляет некоторое значение для хранения, я пытаюсь использовать этот способ, но я получаю сообщение об ошибке:
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
});
}
}
});
и это ошибка:
Uncaught TypeError: Cannot call method 'push' of undefined MeasureListItemComponent.js:18
Можно ли нажать запись для сохранения из компонента? почему я не могу получить доступ к магазину?
мое имя модели - "AxisModel", а пространство имен приложений - "OlapApp"
Ответы
Ответ 1
В component
хранилище не вводится автоматически, как в route
или controller
, когда ваше приложение запускается. Это связано с тем, что компоненты считаются более изолированными.
То, что следует ниже, не считается лучшей практикой. Компонент должен использовать данные, переданные в него, и не знать об этой среде. Лучший способ справиться с этим случаем - использовать sendAction
для создания пузырьков, что вы хотите сделать, и обработать действие с помощью store
в самом контроллере.
@sly7_7 предложение хорошее, и если у вас есть много компонентов, откуда вам нужен доступ к магазину, тогда это может быть хорошим способом сделать это.
Другим подходом к вашему store
может стать обращение к store
к вашей component
окружению controller
. В этом случае не имеет значения, что controller
это потому, что каждый controller
уже ссылается на store
, введенный в него. Итак, теперь, чтобы добраться до вашего store
, можно сделать, получив component
targetObject
, который будет controller
, окружающий component
, а затем получите store
.
Пример:
OlapApp.MeasureListItemComponent = Ember.Component.extend({
...
actions: {
add: function(measure) {
var store = this.get('targetObject.store');
...
}
}
});
См. здесь для рабочего примера.
Надеюсь, что это поможет.
Обновление в ответ на ваш комментарий с вложенными компонентами
Если, например, ваш дочерний компонент является только вложенным на один уровень, вы все равно можете обратиться к родительскому объекту targetObject с помощью parentView
:
App.ChildCompComponent = Ember.Component.extend({
storeName: '',
didInsertElement: function() {
console.log(this.get('parentView.targetObject.store'));
this.set('storeName', this.get('parentView.targetObject.store'));
}
});
Обновлен пример.
Ответ 2
Начиная с Ember v1.10, хранилище можно вводить компонентам с помощью инициализаторов, см. http://emberjs.com/blog/2015/02/07/ember-1-10-0-released.html#toc_injected-properties:
export default Ember.Component.extend({
store: Ember.inject.service()
});
Ответ 3
Текущий способ ember-cli сделать это, похоже, с инициализатором. Очень похоже на ответ @Sly7_7.
Чтобы использовать базовую модель:
ember g initializer component-store-injector
Затем отредактируйте это:
// 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
};
Я считаю, что это добавит хранилище ко всем компонентам.
Украден из https://github.com/ember-cli/ember-cli-todos
Ответ 4
Так как Ember 2.1.0
export default Ember.Component.extend({
store: Ember.inject.service('store'),
});
до Ember 2.1.0 - путь инъекции зависимостей
App.MyComponent = Ember.Component.extend({
store: Ember.computed(function() {
return this.get('container').lookup('store:main');
})
});
до Ember 2.1.0 - путь контроллера
Вы можете передать хранилище как свойство из контроллера:
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'
}
}
});
Магазин доступен на каждом контроллере. Поэтому в родительском представлении вы можете включить компонент следующим образом:
{{view App.MyComponent
store=store
class="some-class"
elementId="some-id"
valueBinding="someValue"
}}
Передача свойств компоненту документируется здесь
Ответ 5
Я не знаю, должны ли компоненты использоваться таким образом. Но если вы хотите, я думаю, вы можете объявить инициализатор и ввести хранилище во все компоненты.
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');
}
})
});
Вот надуманный, но рабочий пример: http://jsbin.com/AlIyUDo/6/edit
Ответ 6
Магазин можно вводить с помощью инъекции зависимостей.
Пример
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');
},
});
Ответ 7
Другим способом, о котором еще никто не упомянул, является просто передать controller.store на компонент, например.
{{my-awesome-component store=controller.store}}