can I change rest model state without using .set() - ember.js

I have model with custom attribute(array of objects). Like this
App.Adapter.registerTransform('images', {
serialize: function(value) {
var ret = []
value.forEach(function(img){
ret.pushObject(img.get('uuid'))
})
if (ret.get('length')) {
return ret.join(',')
} else
return false
},
deserialize: function(value) {
ret = []
if (typeof value !== 'undefined') {
uuids = value.split(',')
for (var i = 0; i < uuids.length; i++) {
var id = uuids[i]
ret.pushObject( App.Image.create({'uuid': id}) )
}
}
return ret
}
})
And my model.
App.Item = DS.Model.extend({
…
images: DS.attr('images')
})
in controller I need commit data, after pushing changes in this property. What I need to do for this case?
uploadImage: function(){
var self = this
uploading.done(function(result) {
self.get('images').pushObject(App.Image.create({uuid:result.uuid}))
console.log(self.get('isDirty')) // false
self.get('store').commit() //nothing to change
}).fail(function(result) {
…
}).always(function() {
…
})
},

Have you tried to do this?
self.notifyPropertyChange('images');

Related

Ember - How to call common validation methods which returns a value

I have a validation method which checks for common validation of values in a input field like empty check, special characters check.
When I call a method using send('methodName'), this will not return a value.
I need to return a value and based on the value I can show messages based on the result.
Code:
Index Template:
{{input value=inputval placeholder='Enter Your Name'}}
<div class="submitdiv" {{action 'submitValue'}}>Submit Name</div>
App.js:
App.IndexController = Ember.ArrayController.extend({
inputval: ''
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['Jeevi', 'James', 'Tony'];
},
actions: {
submitValue: function(){
var self = this;
var temp_val = self.controller.get('inputval');
var is_valid = self.send('validateName', temp_val); //Need a value returned from this method call
if( is_valid ){
self.get('controller').model.addObject(temp_val);
} else {
alert('Enter a Name');
}
},
validateName: function(val){ // Need to return a value based on the validation result
if( val === "" ){
return false;
} else {
return true;
}
}
}
});
JSBin Demo Link
You can use a callback,
js
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['Jeevi', 'James', 'Tony'];
},
actions: {
submitValue: function(){
var self = this;
var temp_val = self.controller.get('inputval');
self.send('validateName', temp_val, function(is_valid){
if( is_valid ){ self.get('controller').model.addObject(temp_val);
} else {
alert('Enter a Name');
}
});
},
validateName: function(val,callback){
if( val === "" ){
callback(false);
} else {
callback(true);
}
}
}
});
http://jsbin.com/ziwosepini/1/edit?html,js
with this approach it is also possible to support ajax/promises, in case a validation needs to be carried out on the server.
http://jsbin.com/cehabojahe/1/edit?html,js

Ember calculated property is recalculated without its dependencies changed

I have an calculated property(named userFields) depending on another calculated property(named userList). When the object(it's a view) is initialised, I found the property "userFields" was calculated hundreds of times with "userList" calculated only once, according to the console log. I don't know why does this happened.
Here are my codes:
App.MainServiceInfoApplicationQueueUserGroupSelectView = Ember.View.extend({
templateName: require('templates/main/service/info/applicationqueues/user_group_select'),
userCollapse: false,
groupCollapse: false,
toggleUserCollapse: function() {
myview = this;
this.set('userCollapse', !this.get('userCollapse'));
},
toggleGroupCollapse: function() {
this.set('groupCollapse', !this.get('groupCollapse'));
},
userList: function() {
console.log('calc user list'); // This is printed only once
var list = [];
App.User.find().forEach(function(item) {
list.push(item);
});
return list;
}.property('App.User.find()'),
groupList: function() {
var list = [];
App.Resourcegroup.find().forEach(function(item) {
list.push(item);
});
return list;
}.property('App.Resourcegroup.find()'),
userFields: function() {
console.log('calc user fields'); // This is printed hundreds of times
// Parse value
var parsedValues = [];
try {
var usersFromValue = this.get('value').split(' ')[0].split('/');
for (var i = 0; i < usersFromValue.length; i++)
parsedValues.push(usersFromValue[i]);
} catch (e) {}
var fields = [];
for (var i = 0; i < this.get('userList').length; i++) {
var item = this.get('userList')[i];
fields.push(Ember.Object.create({
viewClass: Ember.Checkbox.extend({
value: false,
checkedBinding: 'value'
}),
displayName: item.get('userName'),
name: item.get('userName'),
value: parsedValues.contains(item.get('userName'))
}));
}
return fields;
}.property('userList'),
groupFields: function() {
// Parse value
var parsedValues = [];
try {
var groupsFromValue = this.get('value').split(' ')[1].split('/');
for (var i = 0; i < groupsFromValue.length; i++)
parsedValues.push(groupsFromValue[i]);
} catch (e) {}
var fields = [];
for (var i = 0; i < this.get('groupList').length; i++) {
var item = this.get('groupList')[i];
fields.push(Ember.Object.create({
viewClass: Ember.Checkbox.extend({
value: false,
checkedBinding: 'value'
}),
displayName: item.get('groupName'),
name: item.get('groupName'),
value: parsedValues.contains(item.get('groupName'))
}));
}
return fields;
}.property('groupList'),
users: function() {
console.log('calc users'); // This is printed as many times as 'calc user fields' was printed
var list = [];
for (var i = 0; i < this.get('userFields').length; i++) {
var theField = this.get('userFields')[i];
if (parseBoolean(theField.get('value')) == true) list.push(theField.get('name'));
}
return list;
}.property('userFields, userFields.#each.value'),
groups: function() {
var list = [];
for (var i = 0; i < this.get('groupFields').length; i++) {
var theField = this.get('groupFields')[i];
if (parseBoolean(theField.get('value')) == true) list.push(theField.get('name'));
}
return list;
}.property('groupFields, groupFields.#each.value'),
usersString: function() {
return this.get('users').join(', ');
}.property('users'),
groupsString: function() {
return this.get('groups').join(', ');
}.property('groups'),
usersValue: function() {
return this.get('users').join('/');
}.property('users'),
groupsValue: function() {
return this.get('groups').join('/');
}.property('groups'),
value: function() {
return this.get('usersValue') + " " + this.get('groupsValue');
}.property('usersValue', 'groupsValue')
});

Filter with query parameter based on related model

I am trying to filter a collection based on a related model, I have already tried several ways, but can't get it working:
App.BetroundStatsController = Ember.ArrayController.extend({
needs: "betround",
queryParams: ['query_game'],
sortProperties: ['user.nickName'],
query_game: null,
computeFilter: Ember.computed.filterBy('model','game', this.get('query_game')),
filtered: function(){
return this.get('model').filterProperty('game', this.get('query_game'));
}.property('model.#each.game','query_game'),
filteredBets: function() {
var game = this.get('query_game');
var bets = this.get('model');
if (game) {
return bets.filter(function(item){
return(item.get('game.id') == game);
} );
} else {
return bets;
}
}.property('query_game', 'model'),
newestFilter: function(){
var cont = this;
return this.get('model').filter(function(item, index, self) {
if (item.get('game.id') == cont.get('query_game') ) {
return true;
}
})
}.property('model.#each.game'),
});

Serializing outgoing data with Ember.js and Ember-Data

I'm using Ember.js 1.0.0 and Ember-Data-beta2.
I have a model Product which belongsTo Company. When creating a product, the user can select which company it belongsTo in a dropdown menu. This adds "company":"25" to the form post, which for the most part is just what I want. Instead of "company", however, I want the form to submit "company_id". How can I change this?
From what I can tell, Ember-Data serializers only normalize incoming data, not outgoing data. Would this be handled in the adapter? If so, how do I communicate this convention to Ember?
Use the ActiveModelAdapter (see PR here):
App.ApplicationAdapter = DS.ActiveModelAdapter.extend();
Edit: This solution is outdated, use ActiveModelAdapter instead, as suggested by Panagiotis Panagi.
With the recent versions of ember-data you have to override the serializer, in order to get "rails freindly behaivor". Like so:
// See https://github.com/emberjs/data/blob/master/TRANSITION.md
// and http://discuss.emberjs.com/t/changes-with-ds-restadapter/2406/8
App.ApplicationSerializer = DS.RESTSerializer.extend({
normalize: function(type, hash, property) {
var normalized = {}, normalizedProp;
for (var prop in hash) {
if (prop.substr(-3) === '_id') {
// belongsTo relationships
normalizedProp = prop.slice(0, -3);
} else if (prop.substr(-4) === '_ids') {
// hasMany relationship
normalizedProp = Ember.String.pluralize(prop.slice(0, -4));
} else {
// regualarAttribute
normalizedProp = prop;
}
normalizedProp = Ember.String.camelize(normalizedProp);
normalized[normalizedProp] = hash[prop];
}
return this._super(type, normalized, property);
},
serialize: function(record, options) {
json = {}
record.eachAttribute(function(name) {
json[name.underscore()] = record.get(name)
})
record.eachRelationship(function(name, relationship) {
if (relationship.kind == 'hasMany') {
key = name.singularize().underscore() + '_ids'
json[key] = record.get(name).mapBy('id')
} else {
key = name.underscore() + '_id'
json[key] = record.get(name + '.id')
}
});
if (options && options.includeId) {
json.id = record.get('id')
}
return json
},
typeForRoot: function(root) {
var camelized = Ember.String.camelize(root);
return Ember.String.singularize(camelized);
},
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.decamelize(type.typeKey);
data[root] = this.serialize(record, options);
},
serializeAttribute: function(record, json, key, attribute) {
var attrs = Ember.get(this, 'attrs');
var value = Ember.get(record, key), type = attribute.type;
if (type) {
var transform = this.transformFor(type);
value = transform.serialize(value);
}
// if provided, use the mapping provided by `attrs` in
// the serializer
key = attrs && attrs[key] || Ember.String.decamelize(key);
json[key] = value;
}
});
I hope this helps.

Implementation of displaying breadcrumb path in ember with sample code or may be direct me to some repository

Can some one redirect me to some project code or some working example of displaying crumble path in ember?
This code doesn't work for some reason.
ApplicationController = Ember.Controller.extend({
needs: ['breadcrumbs'],
hashChangeOccured: function(context) {
var loc = context.split('/');
var path = [];
var prev;
loc.forEach(function(it) {
if (typeof prev === 'undefined') prev = it;
else prev += ('/'+it)
path.push(Em.Object.create({ href: prev, name: it }));
});
this.get('controllers.breadcrumbs').set('content',path)
}
});
ready : function() {
$(window).on('hashchange',function() {
Ember.Instrumentation.instrument("hash.changeOccured", location.hash);
});
$(window).trigger('hashchange');
}
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller, model) {
Ember.Instrumentation.subscribe("hash.changeOccured", {
before: function(name, timestamp, payload) {
controller.send('hashChangeOccured', payload);
},
after: function() {}
});
}
});
Here you have a starting point:
APP.Breadcrumb = Em.View.extend({
classNames: ['breadcrumb'],
tagName: 'ul',
activeChanged: function () {
var self = this;
Em.run.next(this, function () {
self.set('active', self.get('childViews.firstObject.active'));
});
}.observes('childViews.firstObject.active'),
disabled: function () {
var role = this.get('role');
if (!Em.isEmpty(role)) {
return !this.get('controller.controllers.login').hasRole(role);
}
return false;
}.property("controller.controllers.login.authenticationMediator.roles.#each"),
currentPathChanged: function() {
this.rerender();
}.observes('controller.currentPath'),
template: function () {
var template = [],
controller = this.get('controller'),
router = controller.container.lookup('router:main'),
currentHandlerInfos = router.get('router.currentHandlerInfos');
for (var i = 0; i < currentHandlerInfos.length; i++) {
var name = Em.get(currentHandlerInfos[i], 'name');
if (!(router.hasRoute(name) || router.hasRoute(name + '.index')) || name.endsWith('.index')) {
continue;
}
var notLast = i < currentHandlerInfos.length - 1 && !Em.get(currentHandlerInfos[i + 1], 'name').endsWith('.index');
template.push('<li' + (notLast ? '>' : ' class="active">'));
if (notLast) {
template.push('{{#linkTo "' + name + '"}}');
}
template.push(name);
if (notLast) {
template.push('{{/linkTo}}');
}
if (notLast) {
template.push('<span class="divider">/</span>');
}
template.push('</li>');
}
return Em.Handlebars.compile(template.join("\n"));
}.property('controller.currentPath')
});