I'm trying to get a computed value in my model to update using the .property('key') syntax. My model is like:
App.Camera = Em.Model.extend({
id: attr(),
uid: attr(),
name: attr(),
type: attr(),
refresh: attr(),
thumbnailUrl384x216: function() {
return '%#/devices/%#/thumbnail?width=384&height=216'.fmt(apiBaseUri, this.get('uid'));
}.property('uid', 'refresh'),
thumbnailUrlFull: function() {
return '%#/devices/%#/thumbnail?width=1280&height=720'.fmt(apiBaseUri, this.get('uid'));
}.property('uid', 'refresh')
});
In my camera route I am modifying the refresh variable on an interval, but it is not causing the thumbnailUrl's to update. Am I doing something wrong or does ember-model not support the .property() feature.
I'm able to use the refresh attribute in my template and I see it updating. Any ideas?
The computed value was not updating because I wasn't using the changing refresh value in the computation. Adding that fixed it.
Related
I am having troubles with ember data and I was seeking some help. I am using findRecord to return a single record('location') and then getting a single attribute out of that record('product'). There are other attributes that return just fine(phone, name, etc), however "product" does not return until I have fired the model call at least twice. I have checked my network tab and it is coming in fine from the api, but it does not seem to be loading into ember data(until it fires twice). Has anyone else come across this? I am completely stumped. Thanks!
It looks to me that you have a model that is defined as follows:
/* location model */
export default Model.extend({
phone: attr(),
name: attr(),
/*...*/
product: belongsTo('product')
});
Then the code you are trying to execute is most probably something like:
let name = location.get('name'); // This returns immediately.
let product = location.get('product'); // This does not work as expected
If that is the case then your problem is that you are trying to acquire the product from the location synchronously while it is an asynchronous relationship. This means that you have two options:
Option #1: Make the relationship synchronous (as mentioned by Paul Oliver)
/* location model */
export default Model.extend({
phone: attr(),
name: attr(),
/*...*/
product: belongsTo('product', {async: false})
});
Option #2: Wait for the promise to complete
location.get('product').then(function(product) {
// Do something with product here
});
How do I use a dependency injected field in another field within the ember controller in 2.x Ember?
For instance, I have
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
user: this.get('session').username
How is user able to access the lazily computed values of session?
I noticed that the case above doesn't work as I believe the value of session has been computed yet?
I could use a computed property but I use user as a value in input and I am merely setting a base value.
Not sure if I understood your question correctly, but it seems like you could use computed property function (I usually handle it this way when it comes to DI):
user: Ember.computed.oneWay('session.username')
Or simpler, alias:
user: Ember.computed.alias('session.username')
I have a model like this:
App.Category = DS.Model.extend({
title: DS.attr('string'),
items: DS.hasMany('item', {async: true}),
itemCount: function() {
return this.get('items').get('length');
}.property('items')
});
and it seems I cannot use "property" there if I want to have the UI update everytime a user adds or removes items.
From what I can tell I should be using "observes", but when I use that in place of "property" the handlebars {{itemCount}} tag just renders the function itself as a string.
Any help on getting this to render properly is much appreciated.
I think you can simply use :
{{items.length}}
in your handlebars template.
There's absolutely no need for an observer, computed properties do updates themselves.
And if you really want a computed property named itemCount, it would be :
itemCount: function() {
return this.get('items.length');
}.property('items.length')
Or even better :
itemCount: Ember.computed.alias('items.length')
Like #florent-blanvillain said, just use Ember.computed.alias. But in the future, when writing computed properties based on arrays, you need to use the #each syntax to get it to respond to changes in property values:
itemCount: function() {
return this.get('items').filterBy('isSelected');
}.property('items.#each.isSelected')
Something like that. See the docs on computed properties for more info.
I have an application that saves a user's search criteria in localStorage, where each saved search is represented as an instance of an Ember.js model:
Checklist.SavedSearch = DS.Model.extend({
id: DS.attr('string'),
filters: DS.attr('string')
});
When the "save" button is pressed, the controller creates a model instanced and creates a record for it:
Checklist.savedSearchController = Ember.ArrayController.create({
[..]
save: function(view) {
var saved_seach = Checklist.SavedSearch.createRecord({
id: 'abcd',
filters: '<json>'
});
Checklist.local_store.commit();
}
});
Checklist.local_store is an adapter I created (this is unsurprisingly where the problem probably begins) that has a basic interface that maps createRecord, updateRecord, etc. to a bunch of get/set methods that work with localStorage (loosely based on a github fork of ember-data). The adapter appears to work fine for some basic tests, particularly as findAll has no issues and returns values added manually to localStorage.
Here is the relevant method within Checklist.local_store:
createRecord: function(store, type, model) {
model.set('id', this.storage.generateId);
var item = model.toJSON({associations: true});
this.storage.setById(this.storage_method, type, id, item);
store.didCreateRecord(model, item);
}
The problem is that when createRecord is called by the controller, absolutely nothing occurs. Running it through the debugger, and logging to console, seems to show that the method isn't called at all. I imagine this is a misunderstanding on my part as to how Ember.js is supposed to work. I'd appreciate help on why this is happening.
I come from a ruby and php background, and have perhaps foolishly dived straight in to a JS framework, so any other comments on code style, structure and anything in general are welcome.
Ember Data doesn't change createRecord on the controller so it shouldn't behave any differently. It's possible that there was something related to this in the past, but it's certainly not the case anymore.
I'm trying to allow a user to create a casting and add an array of categories to this casting object. I was trying to use knockout's foreach binding to the array of categories and let users add new categories to the casting. I have created a jsfiddle to illustrate what I'm trying to explain here.
http://jsfiddle.net/msell/ueNg7/16/
The JSON object gets built up correctly as a user modifies a casting, but I cant quite get the list of castings to display.
You have several problems:
You are using Knockout 1.2.1
The foreach binding was not added until Knockout 2.0.
You are not using an observableArray
You need to modify your categories property to be a ko.observableArray(), instead of just an empty array. Otherwise Knockout will not be able to observe when you push to it, and the remove method will not exist.
Your this binding is wrong.
When called from event handlers, this will be set incorrectly. You can fix this in various ways, discussed in length in the Knockout documentation, but one easy fix is to change the references to viewModel instead of to this.
To fix all these, you should upgrade to Knockout 2.0, and change your view model declaration to be
var viewModel = {
name: ko.observable(''),
description: ko.observable(''),
categories: ko.observableArray(),
categoryToAdd: ko.observable(''),
removeCategory: function(category) {
viewModel.categories.remove(category);
},
addCategory: function() {
viewModel.categories.push(new Category(viewModel.categoryToAdd()));
viewModel.categoryToAdd('');
}
};
Here is a corrected JSFiddle: http://jsfiddle.net/ueNg7/19/
You need to use ko.observableArray for you array otherwise Knockout wont know when you change your array and wont update, also you should use a template instead, read here http://knockoutjs.com/documentation/template-binding.html#note_2_using_the_foreach_option_with_a_named_template
var viewModel = {
name: ko.observable(''),
description: ko.observable(''),
categories: ko.observableArray([]),
categoryToAdd: ko.observable(''),
removeCategory: function(category) {
this.categories.remove(category);
},
addCategory: function() {
this.categories.push(new Category(this.categoryToAdd()));
this.categoryToAdd('');
}
};