可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
i have a component and when user click on component it add some value to store,i try to use this way but i get an error :
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
});
}
}
});
and this is error:
Uncaught TypeError: Cannot call method 'push' of undefined MeasureListItemComponent.js:18
is it posible to push record to store from component? why i cant access to store ?
my model name is 'AxisModel' and application namespace is 'OlapApp'
回答1:
In a component
the store does not get injected automatically like in route
's or controller
's when your app starts. This is because components are thought to be more isolated.
What follows below is not considered a best practice. A component should use data passed into it and not know about it's environment. The best way to handle this case would be using sendAction
to bubble up what you want to do, and handle the action with the store
in the controller itself.
@sly7_7 suggestion is a good one, and if you have a lot of components from where you need access to the store then it might be a good way to do it.
Another approach to get to your store
could be to get the store
your component
surrounding controller
has reference to. In this case it doesn't matter which controller
this is because every controller
has already a reference to the store
injected into it. So now to get to your store
could be done by getting the component
's targetObject
which will be the controller
surrounding the component
and then get the store
.
Example:
OlapApp.MeasureListItemComponent = Ember.Component.extend({
...
actions: {
add: function(measure) {
var store = this.get('targetObject.store');
...
}
}
});
See here for a working example.
Hope it helps.
Update in response to your comment having nested components
If for example you child component is only nested one level then you could still refer to parent's targetObject using parentView
:
App.ChildCompComponent = Ember.Component.extend({
storeName: '',
didInsertElement: function() {
console.log(this.get('parentView.targetObject.store'));
this.set('storeName', this.get('parentView.targetObject.store'));
}
});
Updated example.
回答2:
Since Ember v1.10, the store can be injected to components using initializers, see: 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:
Since Ember 2.1.0
export default Ember.Component.extend({
store: Ember.inject.service('store'),
});
before Ember 2.1.0 - dependency injection way
App.MyComponent = Ember.Component.extend({
store: Ember.computed(function() {
return this.get('container').lookup('store:main');
})
});
before Ember 2.1.0 - controller way
You can pass store as property from controller:
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'
}
}
});
Store is available on each controller. So in parent view you can include component as follows:
{{view App.MyComponent
store=store
class="some-class"
elementId="some-id"
valueBinding="someValue"
}}
Passing properties to component is documented here
回答4:
The current ember-cli way to do this appears to be with an initializer. Very similar to the @Sly7_7 answer.
To get a basic model use:
ember g initializer component-store-injector
Then edit this to:
// 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
};
I believe this will add the store to all components.
Stolen from https://github.com/ember-cli/ember-cli-todos
回答5:
I don't know if components are intended to be used such a way. But if you want, I think you can declare an initializer and inject the store into all components.
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');
}
})
});
Here is a contrived but working example: http://jsbin.com/AlIyUDo/6/edit
回答6:
The store can be injected with help of dependency injection.
Example
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:
Another way which no one has yet mentioned is to simply pass controller.store to the component e.g.
{{my-awesome-component store=controller.store}}