I am trying to figure out how to properly perform save using ember data. My models are defined as:
AS.AnalyticsRun = DS.Model.extend({
'exerciseId' : DS.attr('number'),
'exerciseRunId' : DS.attr('number'),
'queued' : DS.attr('boolean'),
'final' : DS.attr('boolean'),
'analyticsRunParameters' : DS.hasMany('analyticsRunParameter')
});
AS.AnalyticsRunParameter = DS.Model.extend({
'name' : DS.attr('string'),
'category' : DS.attr('string'),
'filteredOut' : DS.attr('boolean', { 'default' : false }),
'equalsDefaultValue' : function() {
/* computed property : returns css class name that should be used for the row with parameter having value other than default one*/
return this.get('value') == this.get('default');
}.property('value', 'default'),
'analyticsRun' : DS.belongsTo('analyticsRun')
});
And in my controller I have a function that performs an insert:
createNewAnalyticsRun : function(createRunFrom, createRunFromId){
var self = this;
$.ajax({
type: "POST",
url: AS.baseURL+"analyticsRuns",
data: {"createFrom": createRunFrom, "id" : createRunFromId, "exerciseId" : AS.Analytics.get('exerciseId'), "exerciseRunId" : AS.Analytics.get('exerciseRunId')},
success: function(newAnalyticsRun){
self.get('store').push('analyticsRun', newAnalyticsRun.analyticsRun);
for(var i = 0, len = newAnalyticsRun.analyticsRunParameters.length; i<len; i++){
self.get('store').push('analyticsRunParameter', newAnalyticsRun.analyticsRunParameters[i]);
}
},
dataType: "JSON"
});
}
My route looks like:
AS.AnalyticsRunsIndexRoute = Ember.Route.extend({
model : function() {
var store = this.get('store');
return store.find('analyticsRun',{'exerciseId':1});
}
});
This setup works perfectly(updates my template with added data on save) when my route is setup like:
return store.find('analyticsRun');
But with
return store.find('analyticsRun',{'exerciseId':1});
my template does not get updated upon save even when the added record has exerciseId of 1. When I refresh my page, the newly added data shows up. I am pretty sure that adding filter to the find is causing the issue.
SOLUTION: I ended up using jquery ajax call to rest api to get the data in confluence with the solution provide by #sly7_7, like this
AS.AnalyticsRunsIndexRoute = Ember.Route.extend({
model : function() {
var store = this.get('store'), self = this;
var exerciseId = //get exercise id from some other logic
$.ajax({
type: "GET",
url: AS.baseURL+"analyticsRuns",
data: {"exerciseId" : exerciseId},
success: function(analyticsRunData){
for(var i = 0, len = analyticsRunData.analyticsRuns.length; i<len; i++){
self.get('store').push('analyticsRun', analyticsRunData.analyticsRuns[i]);
}
for(i = 0, len = analyticsRunData.analyticsRunParameters.length; i<len; i++){
self.get('store').push('analyticsRunParameter', analyticsRunData.analyticsRunParameters[i]);
}
},
dataType: "JSON"
});
//perfect since I need to return model anyways without calling find
return store.filter('analyticsRun', function(analyticRun){
return analyticRun.get('exerciseId') == exerciseId;
});
},
setupController : function(controller,model){
this._super(controller,model);
controller.set('analyticsRunSelectOptions',controller.initAnalyticsRunSelectOptions());
this.controllerFor('analysisTemplates').set('model',controller.get('store').find('analysisTemplate'));
}
});
Did you try to use store.filter instead of store.find ? If what you want is filtering and keeping the result as a live array, then filter is the way to go.
In the model hook, I would write something like:
AS.AnalyticsRunsIndexRoute = Ember.Route.extend({
model : function() {
store.find('analyticsRun', {exerciseId: 1});
return store.filter('analyticsRun', function(analyticRun){
return analyticRun.get('exerciseId') == 1;
});
}
});
Related
i'm working with a a router and a controller, and i need to complete some operations on the controller, this is my model code
AcornsTest.StockRoute = Ember.Route.extend({
model: function(params) {
"use strict";
var url_params = params.slug.split('|'),
url = AcornsTest.Config.quandl.URL + '/' + url_params[0] + '/' + url_params[1] + '.json',
stockInStore = this.store.getById('stock', url_params[1]),
today = new Date(),
yearAgo = new Date(),
self = this;
yearAgo.setFullYear(today.getFullYear() - 1);
today = today.getFullYear()+'-'+today.getMonth()+'-'+today.getDate();
yearAgo = yearAgo.getFullYear()+'-'+yearAgo.getMonth()+'-'+yearAgo.getDate();
if(stockInStore && stockInStore.get('data').length) {
return stockInStore;
}
return Ember.$.getJSON(url,{ trim_start: yearAgo, trim_end: today, auth_token: AcornsTest.Config.quandl.APIKEY })
.then(function(data) {
if(stockInStore) {
return stockInStore.set('data', data.data);
} else {
return self.store.createRecord('stock', {
id: data.code,
source_code: data.source_code,
code: data.code,
name: data.name,
description: data.description,
display_url: data.display_url,
source_name: data.source_name,
data: data.data,
slug: data.source_code+'|'+data.code
});
}
});
}
});
and this is my controller
AcornsTest.StockController = Ember.ObjectController.extend({
init: function() {
"use strict";
this.send('generateChartInfo');
},
actions: {
generateChartInfo: function() {
"use strict";
console.log(this.model);
console.log(this.get('model'));
}
}
});
from the controller i'm trying to get access to the model to get some information and format it, and send it to the view
but this.model or this.get('model') always returns null, how can i successful get access to the model from the controller? thanks
You are overriding the init method, but its broken, do this:
AcornsTest.StockController = Ember.ObjectController.extend({
init: function() {
"use strict";
this._super();
this.send('generateChartInfo');
});
You need to call the parent method.
See this test case: http://emberjs.jsbin.com/gijon/3/edit?js,console,output
The model is not ready at init time. If anyone has official docs please share.
I have my router set like :
this.resource('analytics', {path: '/analytics'}, function(){
this.resource('analyticsRuns', {path: ':exerciseRunId/analyticsRuns'},function(){
this.resource('analyticsRun',{path: ':runId'});
});
});
I jump to 'analyticsRuns' route using :
this.transitionToRoute('analyticsRuns',{"exerciseRunId":this.get('selectedExerciseRun.id')});
And my AnalyticsRunsIndexRoute is defined as :
AS.AnalyticsRunsIndexRoute = Ember.Route.extend({
model : function(params) {
var store = this.get('store');
//console.log(params); //returns empty object
//var exerciseRunId = AS.Analytics.get('exerciseRunId');
exerciseRunId = 577;
if(!(exerciseRunId)){
this.transitionTo('analytics');
}
store.find('analyticsRun',{'exerciseRunId':exerciseRunId});
return store.filter('analyticsRun', function(analyticRun){
return analyticRun.get('exerciseRunId') == exerciseRunId;
});
},
setupController : function(controller,model){
this._super(controller,model);
this.controllerFor('analysisTemplates').set('model',controller.get('store').find('analysisTemplate'));
}
});
I was wondering if I could access ":exerciseRunId" value in the AnalyticsRunsIndexRoute. Currently there isnothing set when I check the params arguments passed to this routes' model. On refresh however, the parameter becomes available to the AnalyticsRunRoute but only on refresh. So do I have to play with stateManagement to get the parameter value? or is there simpler way to access it. Thanks.
SOLUTION :
Again lots of thanks to Jeremy for walking through this. Here is how I have set up things now :
I defied routes like :
AS.AnalyticsRunsRoute = Ember.Route.extend({
model : function(params) {
return params;
}
});
AS.AnalyticsRunsIndexRoute = Ember.Route.extend({
model : function(params) {
var parentModel = this.modelFor('analyticsRuns');
var exerciseRunId = AS.Analytics.get('exerciseRunId')||parentModel.exerciseRunId;
var store = this.get('store');
if(!(exerciseRunId)){
this.transitionTo('analytics');
}
store.find('analyticsRun',{'exerciseRunId':exerciseRunId});
return store.filter('analyticsRun', function(analyticRun){
return analyticRun.get('exerciseRunId') == exerciseRunId;
});
},
setupController : function(controller,model){
this._super(controller,model);
this.controllerFor('analysisTemplates').set('model',controller.get('store').find('analysisTemplate'));
}
});
When calling transitionToRoute you should be passing a live object.
this.transitionToRoute('analyticsRuns',this.get('selectedExerciseRun'));
When you transition from route to route the model hook is skipped so it's important that you pass live objects either in transitionToRoute or in a link-to.
[UPDATE] in response to a comment:
If selectedExcerciseRun is not a live object, then you'd need to instantiate a live object before transitioning. Something like this :
var runId = this.get('selectedExerciseRun.id');
var promise = store.find('analyticsRun',{'exerciseRunId':runId});
promise.then(function(analyticsRun){
this.transitionToRoute('analyticsRun',analyticsRun);
});
i have custom url for getting and saving json from server so i created an object for getting json :
App.Cubes = Ember.Object.extend();
App.Cubes.reopenClass({
findAll: function() {
var c = Ember.A();
var xhr = $.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'http://localhost:9095/service.asmx/getCubes',
data: '{}',
success: function(response) {
var data = JSON.parse(response.d);
$.each(data, function(i, v) {
c.pushObject(App.Cubes.create(v));
});
}
});
return c;
}
});
but i need to map these json to model like :
App.Cube = DS.Model.extend({
name: DS.attr('string'),
uniqueName: DS.attr('string')
});
and then using Cube model not using Cubes Object? but i dont know how to map these json or Cubes object to Cube model.it is important for me using ember-data not a simple ember object
Where is your controller code.
App.CubeController = Ember.ObjectController.extend({
actions: {
loadList: function(){
var value = this.get('yourValue');
if(value){
this.set('model', App.Cubes.findAll(value))
}
}
}
})
I'm writing a little ember app without using Ember-Data (using TheMovieDB API) and I don't understand why model is not load when I click on a {{#linkTo}} link, but when I refresh the page manually datas are loaded correctly.
Here is my App.js :
window.App = Ember.Application.create();
App.Router.map(function() {
this.route('about');
this.resource('movie', {
path: '/movie/:movie_id'
})
});
App.IndexRoute = Ember.Route.extend({
setupController: function (controller) {
var movies = [];
$.ajax({
url: "http://api.themoviedb.org/3/movie/popular?api_key=5b088f4b0e39fa8bc5c9d015d9706547",
type: "GET",
async: false,
success: function (data) {
var length = data.results.length;
data.results.forEach(function (item) {
if (item.backdrop_path != null) {
var tmp = item.backdrop_path;
item.backdrop_path = "http://cf2.imgobject.com/t/p/w500/"+tmp+"?api_key=5b088f4b0e39fa8bc5c9d015d9706547"
movies.push(item);
}
})
}
});
controller.set('content', movies);
}
});
App.MovieRoute = Ember.Route.extend({
model: function (param) {
var infos;
/* Important !! */
var promise = Ember.Deferred.create();
$.ajax({
url: "http://api.themoviedb.org/3/movie/"+param.movie_id+"?api_key=5b088f4b0e39fa8bc5c9d015d9706547",
type: "GET",
success: function (data) {
var tmp = data.backdrop_path;
data.backdrop_path = "http://cf2.imgobject.com/t/p/w500/"+tmp+"?api_key=5b088f4b0e39fa8bc5c9d015d9706547";
// infos = Ember.Object.create(data)
promise.resolve(data);
}
});
console.log("MODEL");
return promise;
},
setupController: function (controller, model) {
controller.set('content', model);
}
});
App.Movie = Ember.Object.extend({})
Thanks for your help !
Since you have not specified which model you mean, I'm assuming you mean the movie model, and with my assumption I'm trying to answer.
I think your problem is that your template expects the model coming from a MovieIndexController because you specified a resource in your router map instead of a simple route.
That said, the solution might be to rename your controller to MovieIndexController and respectively the route MovieIndexRoute.
Here the reference my answer is based on, under the paragraph Resources.
Hope it helps
I have a basic person object
PersonApp.Person = DS.Model.extend({
username: DS.attr('string')
});
I have a route to find all people
PersonApp.Router.map(function(match) {
this.resource("person", { path: "/" }, function() {
this.route("page", { path: "/page/:page_id" });
this.route("search", { path: "/search/:page_term" });
});
});
In my route I'm looking at the params coming in
PersonApp.PersonRoute = Ember.Route.extend({
selectedPage: 1,
filterBy: '',
model: function(params) {
if (get(params, 'page_id') !== undefined) {
this.selectedPage = get(params, 'page_id');
} else {
this.selectedPage = 1;
}
if (get(params, 'page_term') !== undefined) {
this.filterBy = get(params, 'page_term');
} else {
this.filterBy = '';
}
console.log(this.selectedPage);
console.log(this.filterBy);
return PersonApp.Person.find();
}
});
My nested routes are using a different model (not person directly) as they contain data that isn't persisted (and really only let me flip a bit on the controller)
Yet when I manually put something on the url or click a link that does a full blown transition the "params" coming into my model hook above are always empty.
Here is the basic page model I'm using (w/ search support)
PersonApp.Page = Ember.Object.extend({
term: ''
});
When a user does a search I have a view that invokes transitionTo
PersonApp.SearchField = Ember.TextField.extend({
keyUp: function(e) {
var model = PersonApp.Page.create({term: this.get('value')});
this.get('controller.target').transitionTo('person.search', model);
}
});
Any way I can pass this "page" model to a nested view and still retain the basic "person" controller context (ie- so I can manipulate the view around this array of model objects)