emberjs: transitionToRoute Error no method 'addArrayObserver - ember.js

From the 'job' route I am trying to transition to 'careers' route using following code.
<script type="text/x-handlebars" data-template-name="job">
<button {{action 'backToCareers' this}}>Back</button>
</script>
The controller with following gives 'Uncaught TypeError: Object # has no method 'addArrayObserver' ' error.
CareerApp.JobController = Ember.ObjectController.extend({
backToCareers: function(){
this.transitionToRoute('careers');
}
});
If I change the code(see below) to provide model object the error changes to 'Uncaught More context objects were passed than there are dynamic segments for the route: careers '
CareerApp.JobController = Ember.ObjectController.extend({
backToCareers: function(){
var jobs = CareerApp.Job.findAll();
this.transitionToRoute('careers', jobs);
}
});
Following is the code of my Model and the router
CareerApp.Job = Ember.Model.extend({
refNo: '',
title: ''
});
CareerApp.Job.reopenClass({
findAll: function(){
return $.getJSON("http://site/jobs").then(
function(response){
var jobs = Ember.A();
response.forEach(function(child){
jobs.pushObject(CareerApp.Job.create(child));
});
return jobs;
}
);
}
});
Router code
CareerApp.Router.map(function(){
this.resource('careers', {path: '/'});
this.resource('job', {path: '/jobs/:job_id'});
});
CareerApp.CareersRoute = Ember.Route.extend({
model:function(){
return CareerApp.Job.findAll();
}
});
CareerApp.CareersController = Ember.ArrayController.extend({
gradJobCount: function () {
return this.filterProperty('isExp', false).get('length');
}.property('#each.isExp')
});

The model hook is expected to return an array but you return a jQuery promise object. findAll should return an empty array which is filled when the callback is executed.
findAll: function() {
var jobs = [];
$.getJSON("http://site/jobs").then(function(response){
response.forEach(function(child){
jobs.pushObject(CareerApp.Job.create(child));
});
});
return jobs;
}

As you pass jobs to CarreersController, this one needs to be an ArrayController, maybe you have to define it manually

Related

Ember json search with multiple TextFields

Ember noob here. I'm basically trying to have multiple input fields for multiple parameters. As the user types into the fields, this sends off a request to a PHP script which returns the relevant JSON and displays it.
Ember 1.6.1 (latest version is a pain to learn as all of the docs are
out of date)
Handlebars 1.3.0
jQuery 1.11.1
Here's the code so far (not working for multiple).
index.html
<script type="text/x-handlebars" data-template-name="search">
{{view App.SearchTextField elementId="bedrooms" valueBinding=bedrooms upKeyAction="searchProperties" placeholder="Bedrooms"}}
{{view App.SearchTextField elementId="suburb" valueBinding=suburb upKeyAction="searchProperties" placeholder="Sydney"}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="search/results">
{{#each}}
<h1>{{bedrooms}} - {{street}} {{suburb}}</h1>
{{/each}}
</script>
apps.js
App = Ember.Application.create();
App.Router.map(function() {
this.resource('search', {path: '/'}, function(){
this.route('results', {path: '/search/:suburb/:bedrooms'});
});
});
App.SearchRoute = Ember.Route.extend({
actions: {
searchProperties: function(suburb, bedrooms) {
console.log(suburb);
this.transitionTo('search.results', suburb, bedrooms);
}
}
});
App.SearchResultsRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('../test/data.php?suburb='+params.suburb+'&bedrooms='+params.bedrooms);
}
});
App.SearchTextField = Ember.TextField.extend({
keyUp: function (e) {
if (e.target.id == 'bedrooms') {
var bedrooms = e.target.value;
} else if (e.target.id == 'suburb') {
var suburb = e.target.value;
}
console.log(suburb + bedrooms);
this.sendAction('action', suburb, bedrooms);
}
});
After some playing around I got it to work using this (looking more jQuery than Ember, but hey it works)
App = Ember.Application.create();
App.Router.map(function() {
this.resource('search', {path: '/'}, function(){
this.route('results', {path: '/search/:suburb/:bedrooms'});
});
});
App.SearchRoute = Ember.Route.extend({
actions: {
searchProperties: function(data) {
this.transitionTo('search.results', data.suburb, data.bedrooms);
}
}
});
App.SearchResultsRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('../test/data.php?suburb='+params.suburb+'&bedrooms='+params.bedrooms);
}
});
App.SearchTextField = Ember.TextField.extend({
keyUp: function (e) {
var data = {suburb:$('#suburb').val(), bedrooms:$('#bedrooms').val()};
this.sendAction('upKeyAction', data);
}
});
Is there a better way to do this?
You are kind of over complicating things IMO,
I'd prefer to observe for the value changes in the controller and act accordingly. Result in much reduced code, and in fact you are actually exploiting the features, the framework provides.
Sample implementation, may need to modify to fulfill your needs
App.SearchController = Ember.ObjectController.extend({
suburb : null,
bedrooms : null,
doSearch : function(){
var model = [{street: this.get('suburb'), bedrooms: this.get('bedrooms')}];
//var model = Ember.$.getJSON('../test/data.php?suburb='+this.get('suburb')+'&bedrooms='+this.get('bedrooms'));
this.transitionToRoute('search.results', model);
}.observes('suburb', 'bedrooms')
});
App.SearchRoute = Ember.Route.extend({
});
App.SearchResultsRoute = Ember.Route.extend({
});
App.SearchTextField = Ember.TextField.extend({});
FIDDLE

property in route undefined in controller

In the IndexRoute of my Ember hello world app, I start a setInterval function that I wish to allow the end user to turn off (with clearInterval) by clicking a dom element in the template, which triggers an action in the IndexController. So, the setIntervalId is set in the IndexRoute, and I need to pass it to clearInterval in the IndexController, but the way I have it below, the setIntervalId is undefined. I also tried to use App.IndexRoute.setIntervalId to no avail.
How would I accomplish this?
(function() {
window.App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_ACTIVE_GENERATION: true
});
App.IndexRoute = Ember.Route.extend({
setIntervalId: 0,
model: function() {
this.setIntervalId = setInterval(this.someInterval, 5000)
},
someInterval: function(){
var datasource = 'http://hackernews/blahblah';
return new Ember.$.ajax({url: datasource, dataType: "json", type: 'GET'}).then(function(data){
return data;
})
},
});
App.IndexController = Ember.ObjectController.extend({
actions: {
clearTimeout: function(){
console.log('clearing interval', this.setIntervalId); //undefined
clearInterval(this.setIntervalId);
}
}
})
})();
template
<script type="text/x-handlebars" data-template-name="index">>
<h1>Hi Babe</hi>
{{ outlet }}
<label {{action "clearTimeout" on="click"}}>clear timeout</label>
</script>
To set the model, you need to return the value in the route’s model function:
model: function() {
return this.setIntervalId = setInterval(this.someInterval, 5000)
}
To access the model in the controller, you need to use this.get('model').
actions: {
clearTimeout: function(){
console.log('clearing interval', this.get('model');
clearInterval(this.get('model'));
}
}

Ember JS cannot createRecord with new ember-data syntax

I am trying to use the new ember-data syntax like explained here: https://github.com/emberjs/data/blob/master/TRANSITION.md (read from Transaction is Gone: Save Individual Records ).
When I hit the save button I get the error Uncaught TypeError: Cannot call method 'save' of undefined in the console. Also in the network tab, there is no POST request to the api.
The template
<script type="text/x-handlebars" data-template-name="landcode/new">
Code: {{input value=code}}<br />
Image: {{input value=image}}<br />
<button {{action 'saveLandcode'}}>opslaan</button>
The app.js (relevant code)
App.Router.map(function() {
this.resource("landcodes"),
this.resource("landcode", function() {
this.route("new");
});
});
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.modelFor('landcode').save(); // does not save
}
}
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
App.Store = DS.Store.extend({
adapter: 'App.ApplicationAdapter'
});
App.Landcode = DS.Model.extend({
code: DS.attr('string'),
image: DS.attr('string')
});
You are using this.modelFor('landcode') this will take the returned model from App.LandcodeRoute, but your model is returned from LandcodeNewRoute. Just use this.currentModel, since you want the model of the current route.
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.currentModel.save();
}
}
});
Your model for should include the route name as well
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.modelFor('landcode.new').save(); // the correct model
}
}
});

Ember Router transitionTo nested route with params

App.Router.map(function() {
this.resource('documents', { path: '/documents' }, function() {
this.route('edit', { path: ':document_id/edit' });
});
this.resource('documentsFiltered', { path: '/documents/:type_id' }, function() {
this.route('edit', { path: ':document_id/edit' });
this.route('new');
});
});
And this controller with a subview event that basically transitions to a filtered document
App.DocumentsController = Ember.ArrayController.extend({
subview: function(context) {
Ember.run.next(this, function() {
//window.location.hash = '#/documents/'+context.id;
return this.transitionTo('documentsFiltered', context);
});
},
});
My problem is that this code works fine when Hash of page is changed.
But when I run the above code NOT w/ the location.hash bit and w/ the Ember native transitionTo I get a cryptic
Uncaught TypeError: Object [object Object] has no method 'slice'
Any clues?
Thanks
UPDATE:
App.DocumentsFilteredRoute = Ember.Route.extend({
model: function(params) {
return App.Document.find({type_id: params.type_id});
},
});
{{#collection contentBinding="documents" tagName="ul" class="content-nav"}}
<li {{action subview this}}>{{this.nameOfType}}</li>
{{/collection}}
The problem is that your model hook is returning an array, while in your transitionTo you are using a single object. As a rule of thumb your calls to transitionTo should pass the same data structure that is returned by your model hook. Following this rule of thumb i would recommend to do the following:
App.DocumentsController = Ember.ArrayController.extend({
subview: function(document) {
var documents = App.Document.find({type_id: document.get("typeId")});
Ember.run.next(this, function() {
return this.transitionTo('documentsFiltered', documents);
});
}
});
Note: I assume that the type_id is stored in the attribute typeId. Maybe you need to adapt it according to your needs.

Why model is not accessible inside controller while accessible in handlebar template?

I have a model of patient object
App.Router.map (function () {
this.resource('patients');
this.resource('patient', {path: ':patient_id'}, function(){
this.resource('dashboard', function() {
this.route('summary');
});
});
});
App.PatientRoute = Ember.Route.extend({
model: function(params) {
return App.Patient.find(params.patient_id);
},
setupController: function(){
console.log("Menu Items:" + App.PatientMenuItem.find() );
this.controllerFor('patient').set('menuItems', App.PatientMenuItem.find());
}
});
App.DashboardSummaryRoute = Ember.Route.extend({
setupController: function(){
this.controllerFor('dashboard.summary').set('content', this.controllerFor('patient').get('model'));
this.controllerFor('dashboard.summary').getPatient();
}
});
App.DashboardSummaryController = Ember.ObjectController.extend({
getPatient:function(){
console.log(this.content.get_allergies);
}
});
App.PatientController = Ember.ObjectController.extend({
menuItems:[],
});
<script type="text/x-handlebars" data-template-name="dashboard/summary">
Summary{{this.content.get_allergies}}
</script>
In the above I am not able to access the same get_allergies in DashboardSummaryController but I am able to access it in handlebars, Can anyone help me what is the mistake ?
Thanks in advance
I don't know if this alone solves the problem, but always use the get() and set() methods when accessing properties. So i would suggest to try this in your getPatient() method:
App.DashboardSummaryController = Ember.ObjectController.extend({
getPatient:function(){
console.log(this.get("content.get_allergies"));
}
});
Why does the template work? The Handlebars expression you have there is automatically translated into the call, i have suggested for your controller method.