I have a template that includes a component.
// pods/workgroup/template.hbs
...
{{workgroup/member-add
wgId=model.id
store=store
peekUser2Workgroup=peekUser2Workgroup
}}
...
Within that component I need to lookup if something is already present in the store.
//somewhere in components/workgroup/member-add/componsent.js
let alreadyInStore = this.store.peekRecord('user2workgroup',u2wId);
I made it work by injecting the store into the component (as above), which of course is bad practise.
So I tried making a property in my parent-controller that does the store lookup:
//in components/workgroup/member-add/componsent.js
let alreadyInStore = this.get('controller').peekUser2Workgroup(u2wId);
//in pods/workgroup/controller.js
peekUser2Workgroup: function(u2wId) {
console.log(this);
console.log(this.store);
return this.store.peekRecord('user2workgroup',u2wId);
}
This works fine as long as I pass the complete store into the compentent as above.
However, if I don't pass the store to the component it get's undefined, although never accessed from the component directly (the store is present in the controller alone).
Logging into console of this gives me surprisingly the component, not the controller, this.store is undefined.
So I've learned, that with this I don't access the controller itself when a function/parameter gets called from outside/a component.
The question is, how can I make the controller to reference to itself with this?
Or how can I access the store when calling a parameter from outside?
Do I really need to pass the controller itself to himself??
like so:
// in component
let alreadyInStore = this.get('controller').peekUser2Workgroup(this.get('controller'), u2wgId);
//in controller
peekUser2Workgroup: function(myself, u2wId) {
console.log(this);
console.log(this.store);
return myself.store.peekRecord('user2workgroup',u2wId);
}
That seems very odd to me, and looks like I'm shifting around even more than I did initially when simply injecting the store to the controller...
Ember: 2.0.1
Ember-Data: 2.0.0
Instead of passing the store into the component as a property, inject it using Ember.service like this:
store: Ember.service.inject()
Then instead of passing in the function, just pass in the id vale you're looking up:
{{workgroup/member-add
wgId=model.id
}}
Now in your component you can fetch the record:
workgroup: function(){
return this.get('store').peekRecord('user2workgroup', this.get('wgId'));
}.property()
Related
This is probably a simple question, but can someone pls clarify the following javascript code?
// 'response' is the JSON data gotten from the backend:
....then(response => {
this.myVar = response.data;
});
// 'myVar' is initialised here:
data: function() {
return {
myVar: null
};
}
I can see how we declare a property 'data' that points to a function that returns an initialised variable 'myVar'.
I don't quite get how 'myVar' is set to the response value. I assume it is a JS technique? Can someone please explain this or provide me a link to such?
* EDIT *
From the responses, it seems I didn't supply enough info (sorry about that - I was assuming it be a simple JS issue). I extracted this code from a tutorial, and it works. The code excerpt is from a .vue file. So I supply the whole file here. The question is still the same.
<template>
<div>
<button class="my-button" v-text="myVar.name" :type="type">My Button</button>
</div>
</template>
<script>
export default {
mounted() {
// The "api/vue" route calls a controller that supplies a JSON object with a single name=>value pair
axios.post("api/vue", {}).then(response => {
// ?? How exactly does myVar get allocated the JSON data?
this.myVar = response.data;
});
},
// initiate the 'myVar' variable
data: function() {
return {
// ?? this object is delared here and somehow accessible to the whole file?
myVar: null
};
},
};
</script>
this whole code makes a Vue Component. In a Vue Component, initial data should be a function, which will be invoked when component created. the object that returned by data() is the initial data for the component, and it's observable(observable means, if you change it, something other will be changed also). the techniche of javascript used here is Object.defineProperty : https://v2.vuejs.org/v2/guide/reactivity.html
base on your code, it says you have a initial data named 'myVar', if you change the value of 'myVar', the dom which bound with 'myVar' will change automatically. in your code, it's the text of the button.
mounted
this is a life-cycle hook, it will be invoked after the component mounted into the dom.
you called an AJAX at here, then you used arrow function to deal with the result of AJAX. arrow function means it's this will not change (here , this equals the Vue Component).
we already have a initial data 'myVar' on this component, now we change it:
this.myVar = response.data;
because it's observable/reactive, the text of the button in your template will be changed.
by the way, your initial myVar is null, so your initial text myVar.name will cause an error
// 'response' is the JSON data gotten from the backend:
....then(response => {
this.myVar = response.data;
});
In this first method, you are fetching data from a server, and assigning it this.myVar (not myVar). so it's local to the component, however...
In the code below, whenever you call data(), you are returning an object with a property myVar encapsulated in it. it is not the same as this.myVar.
// 'myVar' is initialised here:
data: function() {
return {
myVar: null
};
}
I'm not sure what you're trying to achieve here, but these variables are unrelated. And maybe the naming needs some work too, so it's easier for us to see what the purpose of this code is. Either way, if this.myVar is a variable owned by your component, the object returned from the data() method will not have any effect on it, since it's structure is different. the myVar in the Object you are returning in data is a new variable, local to that object.
I have a my-component1.js defined as below;
export default Ember.Component.extend({
prop1: 'abc'
})
The corresponding template my-component1.hbs is as below;
{{#my-yield-component2}}
{{my-other-component3 field=(my-helper prop1)}}
{{/my-yield-component2}}
So I want to display/render my-other-component3 inside my-yield-component2 (as I am using yield)
Inside my-yield-component2, I have the following;
<div>My component with yield</div>
<div>{{yield}}</div>
My question is how do I pass/get access to "prop1" which is actually defined in my-component1, but because I am using yield, it would be rendered in my-yield-component2
So I want to know how to pass "prop1" ?
There is nothing wrong with the way prop1 value of my-component1 is passed to my-other-component3. The context within my-component1's template file is my-component1 itself; hence prop1 will be passed from my-component1 to my-other-component3 even if my-other-component3 is rendered within my-yield-component2. Please take a look at the following twiddle that illustrates what I explained so far works smoothly.
Regarding value passing from my-yield-component2 to my-other-component3 is another story; where you need to yield sth. from the template of my-yield-component2 and pass it to my-other-component3 as follows:
{{#my-yield-component2 as |valueToYield|}}
{{my-other-component3 field=(my-helper prop1) otherField=valueToYield}}
{{/my-yield-component2}}
I have already provided a working twiddle of what I explained above in one of your previous questions.
When I init my vue.js 2.0 app I make window.User object.
That's all going well. Then in some components I'm using it in my
templates:
v-if="this.User.role == 2"
So in some component's this is working and in some not -_- (Cannot read property 'role' of undefined). How is that even possible? In the component's where this is not working I've tried this:
created() {
alert(window.User.role);
}
And the proper result shows up! But in the template it's not working. What could be going on here. Very very frustrating thing.
In my bootstrap.js:
window.User = Laravel.user;
I register all my components the same way:
Vue.component('corporations', require('./components/corporation/Corporations.vue'));
If User is acting like a global variable that you want access to in all components and you want it to be reactive, you can add it to the root Vue's data and then refer to it everywhere else as this.$root.User.
You can also use a mixin to declare a computed that makes it available on all components that use the mixin. Like this:
var mixin = {
computed: {
User: function () { return window.User; }
}
}
The mixin is probably a better route to go.
This is very basic question but i am not finding it any where.
As per my understanding before rendering template correspondin route or component.js's beforeModel() model() etc functions gets called.
What i want to do:
I want to show image of logged in user on my sidenav. User's data is stored in local storage.
My problems here
I am hoping that setting a variable in model and returning the same will solve my problem, but my model method is not being called at all.
My Code:
Template:
{{#paper-sidenav
class="md-whiteframe-z2"
name="right"
open=leftSideBarOpen2
lockedOpen=leftSideBarLockedOpen
position="right"
onToggle=(action (mut leftSideBarOpen2))}}
{{#paper-toolbar as |toolbar|}}
{{#paper-toolbar-tools}}
<img src="http://example.com/users/{{model.username}}.jpg" />
{{/paper-toolbar-tools}}
{{/paper-toolbar}}
{{#paper-content padding=true}}
Çup?
{{/paper-content}}
{{/paper-sidenav}}
Component.js
import Ember from 'ember';
export default Ember.Component.extend({
beforeModel(){
},
model(){
let user = localStorage.get('user');
console.log(user.username);
return user;
},
actions:{
toggle(propName) {
this.toggleProperty(propName);
}
}
});
In console i am getting error "GET http://example.com/users/.jpg 404 (Not Found)", which certainly says that user.username in my template evaluates to null. i tried debugging my model method in chrome's dev tool and found that model is not getting called
Could you please let me know where i'm mistaking?
Ember component does not have model() and afterModel() hooks, what you need to do, is first access the local storage data in afterModel() hook in route and pass the resolved model to component.
Main Route
export default Ember.Route.extend({
model(){
//load data
},
afterModel(model){
//access local store and set to model
model.set('users',data);
}
});
Main route hbs
{{component componetModel=model}}
inside component
import Ember from 'ember';
export default Ember.Component.extend({
init(){
this.set('users', componetModel.users);
}
});
component hbs
{{#each user in users}}
{{user.name}}
{{/each}}
You really have to read the documentation about component. It clearly state what are the lifecycle hooks for each stage,
init
update
delete
https://guides.emberjs.com/v2.11.0/components/the-component-lifecycle/
The only thing the template have access to from route is model so that you can use model directly inside the corresponding template OR pass it to the component(s).
If you need other property for your component you can either set them inside route's setupController(controller, model) hook OR create a controller for that route.
Illustration below is a sample for one specific route,
NOTE: Dashed line represents the runtime generate controller
See image above each "layer" only have access the property OR action direct inside the upper layer (special case is route auto inject model into runtime generated controller).
You do NOT need to specifically define your own controller because if the route cannot find one it will generate one at runtime.
The component is completed isolated from literally anything (unless you inject anything into it). The only way to work with the component is to pass data and action (usually used to handle events) to it.
Summary
(1) The component can only access the data you specifically passed to it (see code below).
{{component-name
internalName=externalName
}}
(2) The template can only access the data that is available inside the controller, either auto-generated one or via ember g controller controller-name. (model property is an exception)
(3) If you want to your template to have route data, using setupController hook.
I wonder if I can modify a property that is in a component via an external controller.
That is, I have an injected component in index.html as follows:
{{ button-feed }}
This component is used in many views.
This component has to be hidden as I get values in the controller, and what I really want is that since this controller, modify a property that hides or shows the button.
The component has the form:
App.ButtonComponent = Ember.Component.extend ({
hideClass: false
});
The property hideClass is used to display or not the button. What I want is to modify this property but using a controller that does not belong to the component button.
I tried to access the property from outside the component, but it is impossible.
You can pass parameters to your component like this:
{{button-feed hideClass=true}}
{{button-feed hideClass=false}}
Also, you could pass in a controller property too.
{{button-feed hideClass=controllerProperty}}
To answer your comment, you can set the controllerProperty by using the code below. Since controllerProperty is bound to the hideClass on your component, changing controllerProperty will change hideClass.
controller.set('controllerProperty', false);
You can read more about setting properties on a controller here.