Errors When Using ember-1.0.0-pre.4.min.js - ember.js

When I use ember-1.0.0-pre.4.min.js on my code, I get the following errors from Chrome's console debugger:
Uncaught TypeError: Object prototype may only be an Object or null ember-1.0.0-pre.4.min.js:18
Uncaught TypeError: Cannot call method 'extend' of undefined
Code:
Win = Em.Application.create({
View: {},
Model: {},
Controller: {}
});
Win.Model.ValuePair = Em.Object.extend({
id: null,
name: null
});
Win.View.BrandKeywordView = Em.TextField.extend({
keyDown: function () {
var value = this.get('value');
if (value) {
Win.Controller.BrandKeywordController.searchBrand(value);
console.log(Win.Controller.BrandKeywordController.content[0].id);
}
}
});
Win.Controller.BrandKeywordController = Em.ArrayProxy.create({
content: [],
searchBrand: function (brandName) {
var me = this;
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json; charset=utf-8',
url: 'brands/default.aspx/Search',
data: '{keyword:"' + brandName + '"}',
success: function (data) {
var brands = $.parseJSON(data.d);
me.content = [];
for (var i = 0, max = brands.length; i < max; i++) {
me.pushObject(Win.Model.ValuePair.create({ id: brands[i].Id, name: brands[i].Name }));
}
}
});
}
});
But then everything works fine when I switch to ember-1.0.beta.2.min.js.
What am I doing wrong?
Which release should I use?
Thanks in advance.

Without having studied your code in detail, my guess would be the routing API. It has completely changed between pre2 and pre3, thus is not backward compatible. Have a look at http://emberjs.com/guides/routing/
So, you really need to "migrate" your code to the new version. It will not just work with the new versions.
NOTE that the API has been freezed with pre4. So, API backward compatibility issues should not arise anymore 'til the next major version of ember js.

Related

Ember-data: Empty payload with .save()

Im stuck trying to.save() a record using Ember-Data 1.3 😵
When I perform a .save() nothing goes wrong but the request payload is empty:
I'm pretty convinced it's an issue with the ember-data request because from the back-end side the only data I got it's "token=blahblahblah". Also I took the request (copy as cURL) and I confirm it's empty:
Here's the .save() code:
var self = this;
this.set('isLoading',true);
return this.store.find('feed', feed_id).then(function(feed) {
//Setting the system_status of the feed to either 4 (archived) or 1 (normal)
feed.set('system_status',param);
//Persist to change to store (and server)
console.log(feed);
feed.save().then(function(){
//success
self.set('isLoading',false);
alert('ok');
},function(){
//Error
self.set('isLoading',false);
alert('error');
}) // => PUT to /feeds/id
});
RESTAdapter:
export default DS.RESTAdapter.extend({
host: 'http://localhost:8000/',
namespace: 'ed',
headers: {
"Content-type": "x-www-form-urlencoded" // workaround for laravel
}});
Model console.log before .save()
Any ideas?
The solution is indeed the Serializer, you can change it to send a POST request instead of a PUT request.
Update the DS.RESTAdapter with this code:
updateRecord: function(store, type, snapshot) {
var data = this.serialize(snapshot, { includeId: true });
var id = snapshot.id;
console.log(snapshot);
var url = ENV.apiUrl + "ed/" + snapshot.typeKey + "/" + snapshot.id;
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'POST',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});

How to refresh a model after a request to API

//Route
url: "https://xxxxxx.com/api/entries",
users: "https://xxxxxx.com/api/users/",
model: function(){
var localData = JSON.parse(localStorage.getItem("user"));
var data = { auth_token: localData.user_token };
return new Ember.RSVP.hash({
logs: Ember.$.ajax({ url: this.get('url'), headers: { "X-Api-Token": data.auth_token } }),
team: Ember.$.ajax({ url: this.get('users'), headers: { "X-Api-Token": data.auth_token } })
});
}
//controller
actions:{
deleteWorklog: function( worklogId ){
var model = this.get('model.logs');
var data = { auth_token: this.get('local_data').user_token };
Ember.$.ajax({
method: "DELETE",
url: this.get('url') + "/" + worklogId,
headers: { 'X-Api-Token': data.auth_token }
}).then(function(data){
//how do i do it?
})
},
loadMore: function(){
var model = this.get('model.logs');
var url = this.get('url');
var today = new Date();
today.setDate(today.getDate() - this.get('from'));
console.log(today);
url += "?from="+ today.toISOString();
Ember.$.ajax({
url: url,
headers: { "X-Api-Token": data.auth_token }
}).then(function(data) {
model.replace(0, model.length, data);
});
var initial = this.get('from') + 10;
this.set('from', initial);
}
}
}
I'm blocked after the request, i need to refresh my model but i've to do cmd + R to see the change, is there a method re-call the model or something like that?
I've added another things maybe help
There's two ways that I can think of. The first is just to call the refresh method on the route. This is by far the simplest. Just call it and Ember will re-call the model hook for that route and any child routes. In your case, I would send an action from your controller to your route, then have your route refresh itself in that action handler.
The second way would be to manually re-get your data and set it on the controller. Perhaps something like this:
// route.js
actions: {
refreshModel: function() {
var route = this;
Ember.$.ajax({ ... }).then(function(data) {
route.get('controller').set('model', data);
});
}
}
However, I wouldn't recommend this method over the first. There are too many variables when dealing with Ember routing and it's easier just to let Ember handle it all.
You either want to use model.reload to refresh the record from the server:
http://emberjs.com/api/data/classes/DS.Model.html#method_reload
Or you may want to delete the record local:
http://emberjs.com/api/data/classes/DS.Model.html#method_deleteRecord
Or you may want to use model.destroyRecord to let Ember do the delete request (remote + local):
http://emberjs.com/api/data/classes/DS.Model.html#method_destroyRecord
I think it would be the best to use model.destroyRecord, but I assume there's a reason you do this manually?

Trying to mock $http in Angular

I am trying to create some basic test coverage of a service that I have created. Here is my service:
App.factory('encounterService', function ($resource, $rootScope) {
return {
encounters: [],
encountersTotalCount: 0,
encountersIndex: 0,
resource: $resource('/encounters/:encounterId', {encounterId:'#encounterId'}, {
search: {
method: 'GET',
headers: {
'RemoteUser': 'jjjyyy',
'Content-Type': 'application/json'
}
}
}),
getMoreEncounters: function() {
var that = this;
that.resource.search({}, function(data) {
that.encountersTotalCount = data.metadata.totalCount;
_.each(data.encounters, function(encounter) {
that.encounters.push(encounter);
});
that.busy = false;
that.offset += 10;
$rootScope.$broadcast('encountersFetched');
});
}
};
});
Here is my test that I cannot get to work:
describe('encounterService', function() {
var _encounterService, httpBackend;
beforeEach(inject(function(encounterService, $httpBackend) {
_encounterService = encounterService;
httpBackend = $httpBackend;
var url = '/encounters/';
httpBackend.when('GET', url).respond([{}, {}, {}]);
}));
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('should return a list of encounters', function() {
_encounterService.getMoreEncounters();
httpBackend.flush();
expect(_encounterService.encounters.size).toBe(3);
});
});
The error I get is
Chrome 31.0.1650 (Mac OS X 10.8.5) Clinical App services encounterService should return a list of encounters FAILED
Error: Unexpected request: GET encounters
No more request expected
at $httpBackend (/Users/mhamm/Developer/clinical/app/bower_components/angular-mocks/angular-mocks.js:1179:9)
at sendReq (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:7611:9)
at $http.serverRequest (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:7345:16)
at wrappedCallback (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:10549:81)
at wrappedCallback (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:10549:81)
at /Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:10635:26
at Scope.$eval (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:11528:28)
at Scope.$digest (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:11373:31)
at Function.$httpBackend.flush (/Users/mhamm/Developer/clinical/app/bower_components/angular-mocks/angular-mocks.js:1453:16)
at null.<anonymous> (/Users/mhamm/Developer/clinical/test/spec/clinical.spec.js:78:21)
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.2.0/$rootScope/inprog?p0=%24digest
at /Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:78:12
at beginPhase (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:11830:15)
at Scope.$digest (/Users/mhamm/Developer/clinical/app/bower_components/angular/angular.js:11364:9)
at Function.$httpBackend.verifyNoOutstandingExpectation (/Users/mhamm/Developer/clinical/app/bower_components/angular-mocks/angular-mocks.js:1486:16)
at null.<anonymous> (/Users/mhamm/Developer/clinical/test/spec/clinical.spec.js:68:21)
I do not fully understand mocking, so I am sure I am doing something basic incorrectly. Please show me what I am doing wrong.
$resource automatically removes the trailing slashes from the url.
From version 1.3.0 there is a fourth argument that allows you to set stripTrailingSlashes: false to keep those.

Ajax without ember data - Uncaught TypeError: Object #<Object> has no method 'forEach'

I'm attempting to build a non blocking async call in an Ember.js app without using Ember Data.
I have the following Ember.js model:
App.Player = Ember.Object.extend({
id: '',
alias: '',
name: '',
twitterUserName: '',
isFeatured: ''
});
App.Player.reopenClass({
getPlayers: function () {
var players = Ember.ArrayProxy.create({ content: [] });
$.getJSON("/api/players").then(function (response) {
response.forEach(function (p) {
players.pushObject(App.Player.create(p));
});
});
return players;
}
});
And I am calling it as follows in my route:
App.IndexRoute = Ember.Route.extend({
model: function (params) {
return App.Player.getPlayers();
}
});
For some reason I am getting the following javascript error:
Uncaught TypeError: Object # has no method 'forEach'
I've tried a few variants I have seen around but nothing seems to work. Any help would be appreciated...
EDIT - Found the solution with some help from Darshan, here's the working code:
App.Player.reopenClass({
getPlayers: function () {
var players = [];
$.ajax({
url: "/api/players",
}).then(function (response) {
response.players.forEach(function (player) {
var model = App.Player.create(player);
players.addObject(model);
});
});
return players;
}
});
Your response.forEach suggests that you are expecting the json response body to be an array. It is probably wrapped in some root element like players or data like so.
{
"players": [...]
}
If that is the case you need to use forEach on that root element like response.players.forEach.
You also want to restructure that code to return a promise directly. The Ember router will then pause until your json is loaded and only proceed after it finishes. Something like this,
getPlayers: function () {
return $.getJSON("/api/players").then(function (response) {
var players = Ember.ArrayProxy.create({ content: [] });
response.players.forEach(function (p) {
players.pushObject(App.Player.create(p));
});
return players;
});
}
Returning players resolve the promise. And Ember understands that when a promise resolves that result is the model.

Fullcalendar, backbone.js, Cannot edit event

So, I think I am in over my head here. I am trying to get fullcalendar to work with backbone and django. I am still learning all of this but I can now make new events and save them via django-tastypie, and they do show up in the calendar, wohoo! However, I can not edit or drag them. Uncaught TypeError: Cannot call method 'isNew' of undefined line 96, is what I get when events are clicked and Uncaught TypeError: Cannot call method 'save' of undefined line 78. I have done my best to figure this out, but no success. Why is this.model.isnew() undefined in render and the same for save? I do not fully understand all of this so I have probably made some stupid mistake somewhere or misunderstood how everything works. I would be grateful if anyone could give me a hint.
I added console.log(fcEvent); to eventClick, and when I inspect it, it says start and end dates are invalid. Does anyone know what that means? If I inspect the same object just after it was added with addOne, the dates are valid. I am also using https://github.com/PaulUithol/backbone-tastypie if that matters.
edit: Tried this to make sure events.fetch() succeeded, this resulted in no events in the calendar whatsoever. Does that mean that events.fetch() never succeeds? I can see "GET /api/event/ HTTP/1.1" 200 6079 in the log.
alternative fetch:
events.fetch({
success: function(){
new EventsView({el: $("#calendar"), collection: events}).render();
}});
Original program:
$(function(){
var Event = Backbone.Model.extend();
var Events = Backbone.Collection.extend({
model: Event,
url: '/api/event/'
});
var EventsView = Backbone.View.extend({
initialize: function(){
_.bindAll(this);
this.collection.bind('reset', this.addAll);
this.collection.bind('add', this.addOne);
this.collection.bind('change', this.change);
this.collection.bind('destroy', this.destroy);
this.eventView = new EventView();
},
render: function() {
this.$el.fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,basicDay'
},
selectable: true,
selectHelper: true,
editable: true,
ignoreTimezone: false,
disableResizing:false,
select: this.select,
defaultView: 'agendaWeek',
eventClick: this.eventClick,
eventDrop: this.eventDropOrResize,
eventResize: this.eventDropOrResize,
events: 'events'
});
},
addAll: function() {
this.$el.fullCalendar('addEventSource', this.collection.toJSON());
},
addOne: function(event) {
this.$el.fullCalendar('renderEvent', event.toJSON(), true);
},
select: function(start, end, allDay) {
var eventView = new EventView();
console.log('select');
eventView.collection = this.collection;
eventView.model = new Event({start: start, end: end, allDay: allDay});
eventView.render();
},
eventClick: function(fcEvent) {
console.log('click');
this.eventView.collection = this.collection;
this.eventView.model = this.collection.at(fcEvent.id);
console.log(fcEvent);
this.eventView.render();
},
change: function(event) {
// Look up the underlying event in the calendar and update its details from the model
var fcEvent = this.$el.fullCalendar('clientEvents', event.get('id'))[0];
fcEvent.title = event.get('title');
fcEvent.color = event.get('color');
console.log('change');
this.$el.fullCalendar('updateEvent', fcEvent);
},
eventDropOrResize: function(fcEvent) {
console.log(fcEvent);
// Lookup the model that has the ID of the event and update its attributes
this.eventView.collection.at(fcEvent.id).save({start: fcEvent.start, end: fcEvent.end});
},
destroy: function(event) {
this.$el.fullCalendar('removeEvents', event.id);
}
});
var EventView = Backbone.View.extend({
el: $('#eventDialog'),
initialize: function() {
_.bindAll(this);
},
render: function() {
var buttons = {'Ok': this.save};
if (!this.model.isNew()) {
_.extend(buttons, {'Delete': this.destroy});
}
_.extend(buttons, {'Cancel': this.close});
this.$el.dialog({
modal: true,
title: (this.model.isNew() ? 'New' : 'Edit') + ' Event',
buttons: buttons,
open: this.open
});
return this;
},
open: function() {
this.$('#title').val(this.model.get('title'));
this.$('#color').val(this.model.get('color'));
},
save: function() {
this.model.set({'title': this.$('#title').val(), 'color': this.$('#color').val(),});
console.log('save');
if (this.model.isNew()) {
this.collection.create(this.model, {success: this.close,wait: true });
} else {
this.model.save({}, {success: this.close});
}
},
close: function() {
this.$el.dialog('close');
},
destroy: function() {
this.model.destroy({success: this.close});
}
});
var events = new Events();
new EventsView({el: $("#calendar"), collection: events}).render();
events.fetch();
});
You can try this. The issue comes down to an undefined Model.
On this line.
select: function(start, end, allDay) {
var eventView = new EventView();
eventView.collection = this.collection;
eventView.model = new Event({start: start, end: end, allDay: allDay});
eventView.render();
},...
Change it to. I have a feeling that your Model is not being instantiated properly.
select: function(start, end, allDay) {
var eventView = new EventView({
collection: this.collection,
model: new Event({start: start, end: end, allDay: allDay})
});
eventView.render();
},
Another issue is, you're instantiating the EventsView and passing in the collection and models before the fetch call.
var events = new Events();
$.when(events.fetch()).then(function() {
// Create the Events view when the Events asynchronous operation completes.
new EventsView({el: $("#calendar"), collection: events}).render();
});
Edit: here's a JS Bin for additional changes.
I got this working except for events not actually disappearing from the calendar, even though they are deleted in the database. I dont know if this is the correct way to do this, probably not, but it worked. Model was undefined in EventView so I had to get the model from the collection and pass it on to EventView.
eventClick: function(fcEvent) {
console.log(fcEvent.id);
this.mymodel = this.collection.where({'id':fcEvent.id})[0];
this.eventView = new EventView({collection: this.collection, model: this.mymodel})
this.eventView.render();
},
change: function(event) {
// Look up the underlying event in the calendar and update its details from the model
var fcEvent = this.$el.fullCalendar('clientEvents', event.get('id'))[0];
fcEvent.title = event.get('title');
fcEvent.color = event.get('color');
console.log('change');
this.$el.fullCalendar('updateEvent', fcEvent);
},
eventDropOrResize: function(fcEvent) {
console.log(fcEvent);
// Lookup the model that has the ID of the event and update its attributes
this.collection.where({'id':fcEvent.id})[0].save({start: fcEvent.start, end: fcEvent.end});
},