Create a computed bool using relationship field Ember - ember.js

I'm trying figure out how my computed property identify if my relationship was set.
Project = Model.extend({
participantes: hasMany('author')
...
I need change my css based if has a author.
{{my-component project=project}}
//---------- my-component.js
export default Ember.Component.extend({
classNameBindings: ['hasParticipante'],
hasParticipante = Ember.computed('project.participantes', function(){
//the code I need gonna here
})});

This will probably not work since a relationship is always a PromiseArray or PromiseObject. Probably you can check on the content:
Ember.computed.bool('author.content')
Your component seems completely wrong:
You can't use = in Object creation.
Ember.get needs two parameters. The context and the property, like get(this, 'post').
You should not use arrow functions for computed properties since you have no access to the object then.
But you don't need that line at all. Just do classNameBindings: ['hasAuthor']

Related

How is Sorting achieved in an Ember model without using Array Controller?

Every google result is about an ArrayController sorting. Need a sorting mechanism without using ArrayController.
There is a model where there are sort params. Like say 'sortOrder' as one of the properties in the model (which will be from a back end).
Will be rendering this model using #each but this should do the iteration based on the sortOrder property and not the model's ID property.
In Ember 2.0 SortableMixin is deprecated and is on its way out too.
In the Controller (not the ArrayController) you may define a new computed property like SortedUsers1,2,3 below:
export default Ember.Controller.extend({
sortProps: ['lastName'],
sortedUsers1: Ember.computed.sort('model', 'sortProps'),
sortedUsers2: Ember.computed.sort('content', 'sortProps'),
sortedUsers3: Ember.computed('content', function(){
return this.get('content').sortBy('lastName');
})
});
The assumption above is that the model itself is an array of users with lastName as one of user properties. Dependency on 'model' and 'content' look equivalent to me. All three computed properties above produce the same sorted list.
Note that you cannot replace 'sortProps' argument with 'lastName' in sortedUsers1,2 - it won't work.
To change sorting order modify sortProps to
sortProps: ['lastName:desc']
Also if your template is in users/index folder then your controller must be there as well. The controller in users/ would not do, even if the route loading model is in users/.
In the template the usage is as expected:
<ul>
{{#each sortedUsers1 as |user|}}
<li>{{user.lastName}}</li>
{{/each}}
</ul>
Here is how I manually sort (using ember compare)
import Ember from "ember";
import { attr, Model } from "ember-cli-simple-store/model";
var compare = Ember.compare, get = Ember.get;
var Foo = Model.extend({
orderedThings: function() {
var things = this.get("things");
return things.toArray().sort(function(a, b) {
return compare(get(a, "something"), get(b, "something"));
});
}.property("things.#each.something")
});
You just need to include a SortableMixin to either controller or component and then specify the sortAscending and sortProperties property.
Em.Controller.extend(Em.SortableMixin, {
sortAscending: true,
sortProperties: ['val']
});
Here is a working demo.
In situations like that, I use Ember.ArrayProxy with a Ember.SortableMixin directly.
An ArrayProxy wraps any other object that implements Ember.Array
and/or Ember.MutableArray, forwarding all requests. This makes it very
useful for a number of binding use cases or other cases where being
able to swap out the underlying array is useful.
So for example, I may have a controller property as such:
sortedItems: function(){
var items = Ember.ArrayProxy.extend(Ember.SortableMixin).create({content: this.get('someCollection')});
items.set('sortProperties', ['propNameToSortOn']);
return items;
}.property()
Like so: JSBin

model not getting set while using render helper in ember -cli

I am using ember-cli and there is one controller which gets using a render helper and hence no route. Example
{{render 'ref-type' ref-type}}
Now inside the controller ref-type
export default Ember.Controller.extend({
actions{
isShown: function() {
var m = this.get('model'); //here model is undefined can i know why?
}
}
});
and model ref-type is
export default Ember.Object.extend({
getData: function(){
return 'xyz'; //data is returned hre
}
});
why am i not able to access model in the controller.
Adding a raw JSBin example
JSBIN
Should the model always be DS.Model.extend? i do not think so.
Also Instead of ref-type i have used 'sample' as the name, so that it is easier to understand
You never initialize your model. According to your JSBin example you must have property named sample in your TodosController. ember will not create an object by itself. I have edited your JSBin. It might not be the best approach but I tried to explain what is going on.
If you put log {{log sample}} just above your render helper you will notice that your sample property is already undefined.

Unbound properties as arguments for components and views

I'm in the process of optimizing my Ember application by following some of the tips given in this presentation. I'm wondering how I can give unbound properties as arguments to components and views. For instance in
{{my-component arg=unboundProperty}}
I want unboundProperty to be unbound, i.e. it takes as value its first non-null value (set after the models in the route has been resolved) but does not propagate to the component when its value changes. How can I achieve that?
If you really need to do it you can use a computed property without defining dependencies. The computed property will be calculated the first time it's requested, and then it will never think it needs to update, so it will never update.
App.FooController = Ember.ObjectController.extend({
realProperty: 'fooBar',
unboundProperty: function(){
return this.get('realProperty');
}.property()
});
{{my-component arg=unboundProperty}}
You could do the same thing in your component
App.MyComponentComponent = Ember.Component.extend({
readOnceArg: function(){
return this.get('arg');
}.property()
})

In Ember.js how to notify an ArrayController's corresponding itemController, when a property on the ArrayController changes

I have an EmailsController (ArrayController), which stores all the emails. I have an EmailController (ObjectController) that has a parameter that stores if the actual Email is selected or not. I am trying to implement a button in the emails template, that selects or deselects all the Emails. So somehow I need to notify the EmailController via an action of the EmailsController and change the EmailController's isChecked parameter.
I am trying to use the itemController, the needs, and the controllerBinding parameters, but nothing works.
Here are the controllers:
App.EmailsController = Ember.ArrayController.extend({
needs: ["Email"],
itemController: 'Email',
checkAll: true,
actions: {
checkAllEmails: function() {
this.toggleProperty("checkAll");
console.log(this.get("checkAll"));
}
}
});
App.EmailController = Ember.ObjectController.extend({
needs: ["Emails"],
controllerBinding: 'controllers.Emails',
isChecked: true,
checkAllChanged: function() {
//this should execute, but currently it does not
this.set("isChecked",this.get('controller.checkAll'));
}.property("controller")
});
Here is the corresponding jsFiddle: http://jsfiddle.net/JqZK2/4/
The goal would be to toggle the selection of the checkboxes via the Check All button.
Thanks!
Your mixing a few different mechanisms and your using a few wrong conventions. It's not always easy to find this stuff though, so don't fret.
Referencing Controllers
Even though controllers are created with an Uppercase format, the are stored in the lowercase format and your needs property should be:
needs: ['emails'],
You then access other controllers through the controllers property:
this.get('controllers.emails.checkAll')
Computed Properties
Computed properties can be used as a getter/setter for a variable and also as a way to alias other properties. For example, if you wanted the isChecked property on the Email controller to be directly linked to the value of the checkAll property of the Emails controller, you could do this:
isChecked: function() {
return this.get('controllers.emails.checkAll');
}.property('controllers.emails.checkAll')
Although computed properties can do much more, this basic form is really just a computed alias, and there is a utility function to make it easier:
isChecked: Ember.computed.alias('controllers.emails.checkAll')
Observables
An observable basically creates a method that will be called when the value it observes changes. A computed alias would cause all items to uncheck or check whenever you clicked on any one of them, since their isChecked property is linked directly to the checkAll property of the parent controller. Instead of your checkAllChanged method identifying as a property it should use observes:
checkAllChanged: function() {
this.set("isChecked",this.get('controllers.emails.checkAll'));
}.observes("controllers.emails.checkAll")
This way when the checkAll property changes on the parent controller, this method updates the isChecked properties of all items to its value, but if you uncheck or check an individual item, it doesn't affect the other items.
Bindings
Bindings are somewhat deprecated; from reading issues on the Ember github repository I believe the creators of Ember seem to favor using computed properties, aliases, and observables instead. That is not to say they don't work and if your goal was to avoid having to type out controllers.emails every time, you could create one like you did (I wouldn't call it controller though, cause thats really quite ambiguous):
emailsBinding: 'controllers.emails'
Using a computed alias instead:
emails: Ember.computed.alias('controllers.emails')
You could then change your observer to:
checkAllChanged: function() {
this.set("isChecked",this.get('emails.checkAll'));
}.observes("emails.checkAll")
Heres an updated version of your jsFiddle: http://jsfiddle.net/tMuQn/
You could just iterate through the emails, changing their properties from the parent controller. You don't need to specify needs or observe a variable.
App.EmailsController = Ember.ArrayController.extend({
itemController: 'email',
actions: {
checkAllEmails: function() {
this.forEach(function(email) {
email.toggleProperty("isChecked");
});
}
}
});
Also, you typically don't set initial values like you did with isChecked = true; I believe that's creating a static shared property on the prototype (not what you intended). Instead, set the property on init, or pass it in from your original json data.
See the code: http://jsfiddle.net/JqZK2/5/

ObjectController and ArrayController

I am learning emberjs form trek.github.com. That tutorial used both Em.ObjectController and Em.ArrayController. And There is also Em.Controller.
I am confused when to use them, I guess Em.ObjectController is for single object, Em.ArrayController is for array and Em.Controller is just for ApplicationController.
Is there any blessed rule for when to use which?
Usually, if your Controller represent a list of items, you would use the Ember.ArrayController, and if the controller represents a single item, you would use the Ember.ObjectController. Something like the following:
MyApp.ContactsController = Ember.ArrayController.extend({
content: [],
selectedContact: null
});
MyApp.SelectedContactController = Ember.ObjectController.extend({
contentBinding: 'contactsController.selectedContact',
contactsController: null
});
Then in your Ember.Router (if you use them), you would connect the two inside the connectOutlets function:
connectOutlets: function(router) {
router.get('selectedContactController').connectControllers('contacts');
}
Edit: I have never used the Ember.Controller. Looking at the source code, it seems like you might want to use this if you are building a custom controller that doesn't fit in with the two other controllers.
The general rule is that it depends on model from route.
If model is an array then you should use ArrayController. It will allow you to implement in easy way sorting or filtering in future. ArrayController is connecting usually ObjectControllers.
When your model is an instance of Ember Object then you should use ObjectController. It takes place when you are using for instance ember data. With Objectcontroller you can access model properties directly. You don't have to write model.property each time.
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return Ember.Object.create({name: 'Mathew'});
}
});
My name is {{name}}
Finally, when one doesn't have model there is an ideal situation to use just Ember.Controller. It is not going to allow direct access to model properties as ObjectController.