Why does not LSAdapter trigger the loading event in Ember.js? - javascript

I am working with the LSAdapter , and trying to get the loading event work .
I found this strange problem ,that loading event seems not working properly.
Here is a simple page .
--When we work with DS.FixtureAdapter . The loading event works fine
--When we work with DS.LSAdapter .the loading event does not work ?
Am I making any mistakes?
<script type="text/x-handlebars" data-template-name="application">
<h1>ember-latest jsbin</h1>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{input value = newBookTitle action= 'newBook'}}
<ul>
{{#each}}
<li>{{title}} </li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="loading">
<div id = 'global-loading'>
<h2>GLOBAL LOADING</h2>
</div>
</script>
<script>
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_VIEW_LOOKUPS: true
});
//Why does LSAdapter doesnot trigger the loading event?
// App.ApplicationAdapter = DS.LSAdapter.extend({namespace: 'App-test-loading'});
// FixtureAdapter works fine with loading event
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.Book = DS.Model.extend({
title: DS.attr('string'),
});
App.Book.FIXTURES = [
{
id: 1,
title: 'Learn Ember.js',
},
{
id: 2,
title: 'Nothing more'
}
];
App.ApplicationRoute = Ember.Route.extend({
actions: {
loading: function() {
alert('laoding');
}
}
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('book');
}
});
App.IndexController = Ember.ArrayController.extend({
newBookTitle:'',
actions:{
newBook:function(){
var _nb = this.get('newBookTitle');
if(!_nb) return ;
var _book = this.store.createRecord('book',{
id: Math.random().toString(32).slice(2).substr(0, 5),
title: _nb
});
_book.save();
this.set('newBookTitle', '');
}
}
});
</script>
_______UPDATE_________
With the kind help from #GJK
I solve it in this way :
/*IndexRoute model hook*/
var books = this.store.find('book');
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
resolve(books);
}, 10);
});
also get help from
1 How do I create a promise in Ember.js for an Ember-data model
2 http://jsbin.com/ipehoj/1/edit

It's because the FixtureAdapter tries to simulate a remote server while the LSAdapter doesn't. From the FixtureAdapter:
return this.simulateRemoteCall(function() {
The Fixture adapter actually waits a set amount of time to more closely resemble an actual server call (which is the whole purpose of the FixtureAdapter). But look at the LSAdapter:
return Ember.RSVP.resolve(record);
It returns a promise that resolves almost immediately, leaving no time for your loading event to get called.
The LSAdapter is supposed to be a production-ready adapter that stores your data in the browser. Because it's stored in the browser, there are (almost) no loading times. The FixtureAdapter on the other hand, is supposed to simulate a production-ready adapter that will having loading times. Their purposes are different, you shouldn't use them interchangeably.

Related

Ember data store return undefined record from FIXTURES

I am new in ember and i am trying to simply get log of items stored by Fixtures model and i cannot. Here is what I have done:
app.js
App = Ember.Application.create();
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter.extend()
});
App.Documenter = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
App.Documenter.FIXTURES = [
{ id: 1, firstName: 'Trek', lastName: 'Glowacki' },
{ id: 2, firstName: 'Tom', lastName: 'Dale' }
];
App.IndexRoute = Ember.Route.extend({
controllerName: 'application',
actions: {
addtostore: function () {
},
displaystore: function () {
var obj = this.store.all('documenter');
console.log(obj.objectAt(0).firstName); //here i get undefined
}
}
});
html:
<script type="text/x-handlebars">
<h2> Ember POC</h2>
<p>POC</p>
{{outlet}}
<button {{action 'displaystore'}}>TestButton</button>
</script>
I've looked at few answers already on stackoverflow:
Ember-Data Fixture Adapter
Ember App Kit with ember data
but still I dont get, why button TestButton dont log into console. I tried many ways but always it is undefined
No need to define the store, and your adapter should be defined like so:
App.ApplicationAdapter = DS.FixtureAdapter;
And all only returns records that have already been found and are in the store. The FIXTURES hash isn't automatically loaded into the store, you still need to use find in order to get records from the FIXTURES hash.
displaystore: function () {
this.store.find('documenter').then(function(records){ // this is async
console.log(records.get('firstObject.firstName'));
});
}
It's doubtful you would want to call find from the action like this, since it'd call back to the server each time, generally you'd get the records in the route (or even prime your store in the route so you can use all).
Because I am fresh in Ember, I made few common mistakes. I did not understand routes, handlebars, etc., and I messed up. The problem was that I did not assign the model to a controller.
App.IndexRoute = Ember.Route.extend({
model: function () {
var store = this.get('store');
return store.findAll('documenter');
}
});

Model reloading with Ember Data

I'm trying to poll for more data using the documented model.reload() function
App.ModelViewRoute = Ember.Route.extend({
actions: {
reload: function() {
this.get('model').reload();
}
}
});
But i'm getting an error message saying...
undefined is not a function TypeError: undefined is not a function
Is there a better way of doing this, it seems like I cannot access the model in this way from the route?
Here is the router
App.Router.map(function() {
this.route('video', { path: '/videos/:video_id' });
});
Here is the route
App.VideoRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('video', params.video_id);
},
actions: {
reloadModel: function() {
// PROBLEM HERE
// this.get('model').reload();
Ember.Logger.log('reload called!');
}
}
});
Here is the model
App.Video = DS.Model.extend({
title: DS.attr('string'),
status: DS.attr('string')
});
And the templates
<script type="text/x-handlebars" data-template-name="application">
<h1>Testing model reloading</h1>
{{#link-to "video" 1}}view problem{{/link-to}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="video">
<h1>Video</h1>
<h2>{{title}}</h2>
{{model.status}}
<p><button {{action 'reloadModel'}}>Reload model</button></p>
</script>
I've made a jsbin of the issue here:
http://jsbin.com/wofaj/13/edit?html,js,output
I really can't understand why the reload gives me this error. Any advice would be much appreciated.
Thanks
Since model already exists as a hook on Ember.Route, you cannot get that as a property.
Instead you can do the following:
this.modelFor('video').reload();
Technically you could do this.get('currentModel').reload(); too, but that's undocumented and probably won't be available in the future.
The refresh method of the route would do what you're after
App.VideoRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('video', params.video_id);
},
actions: {
reloadModel: function() {
this.refresh()
}
}
});
API docs
The route model function provides a hook to load your controller data. There is a specific section at the ember guide.
1) If you want to access your content, it would be like:
reload: function() {
this.controller.get('content');
}
2) reload is a method available of ember-data objects. In your example, you are loading a js object ({ id:2, title:"Test video title 2", status:"downloading"}).

Emberjs nothing handled this action

Error : Uncaught Error: Nothing handled the action 'rollDice'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.
I made sure that the method in the controller had the same name as the action.
???
HTML portion
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
{{#linkTo "roll"}}Lets roll dice!{{/linkTo}}
</script>
<script type="text/x-handlebars" id="roll">
<p class="centerme">A Dice Roller.</p>
<p> </p>
<p>Click to play!<br/>
<button id="play" {{action 'rollDice'}}>Roll Dice</button>
</p>
<section id="roll-wrap">Dice stuff</section>
<script>
Controller
DiceRoller.RollController = Ember.ObjectController.extend({
var diceModel = this.get('model');
actions: {
rollDice: function () {
var x=[270,1080,1440,810];
var rand1=Math.floor(Math.random()*4);
var rand2=Math.floor(Math.random()*4);
diceModel.set('rotateXvalue',x[rand1]+"deg");
diceModel.set('rotateYvalue',x[rand2]+"deg");
diceModel.save();
}.property('diceModel.rotateXvalue','diceModel.rotateYvalue')
}
});
Routing
DiceRoller.Router.map(function() {
this.resource("roll");
});
DiceRoller.IndexRoute = Ember.Route.extend({
redirect: function(){
this.transitionTo("roll");
}
});
DiceRoller.DiceRoute = Ember.Route.extend({
model: function() {
return this.store.find('Dice');
}
});
Model
DiceRoller.Dice = DS.Model.extend({
rotateXvalue: DS.attr('string'),
rotateYvalue: DS.attr('string')
});
DiceRoller.Dice.FIXTURES = [
{
rotateXvalue: '40deg',
rotateYvalue: '37deg'
}
];
http://jsbin.com/qosujasi/1/
My JS bin, so far it gives me an error about setting the content of an object proxy.
You've named your controller incorrectly. The correct controller for the roll route would be DiceRoller.RollController.
In the RollController, you should get the model inside the roleDice action and you don't need the list of properties. That's for computed properties, not actions.
DiceRoller.RollController = Ember.ObjectController.extend({
actions: {
rollDice: function () {
var diceModel = this.get('model');
var x=[270,1080,1440,810];
var rand1=Math.floor(Math.random()*4);
var rand2=Math.floor(Math.random()*4);
diceModel.set('rotateXvalue',x[rand1]+"deg");
diceModel.set('rotateYvalue',x[rand2]+"deg");
diceModel.save();
}
}
});
Check out this jsBin.
You need to create the model record to be able to set values on it in your route, like this:
DiceRoller.RollRoute = Ember.ObjectController.extend({
model:function() {
return this.store.createRecord('dice');
}
});
I am fresh new to Ember.js and also struggling, but for me it worked to either move actions: {...} from controller to route:
DiceRoller.DiceRoute = Ember.Route.extend({
model: function() {
return this.store.find('Dice');
},
actions: {...} // move actions here
});
OR to use ApplicationController instead of RollController:
DiceRoller.ApplicationController = Ember.ObjectController.extend({
var diceModel = this.get('model');
actions: {
rollDice: function () {
var x=[270,1080,1440,810];
var rand1=Math.floor(Math.random()*4);
var rand2=Math.floor(Math.random()*4);
diceModel.set('rotateXvalue',x[rand1]+"deg");
diceModel.set('rotateYvalue',x[rand2]+"deg");
diceModel.save();
}.property('diceModel.rotateXvalue','diceModel.rotateYvalue')
}
});
Not saying it is the correct way! Just saying it worked for me - still learning ;-)
When you follow Ember official tutorial, and get to the Templates->Actions chapter, you will probably run into this error on first example because this example uses Components that are explained later. I tried adding action to templates/about.hbs and creating component/about.js with action handler, but these two wouldn't work together. Im guessing the trick is to define hbs file in templates/components/ but before that I got the action working by creating
controllers/about.js like this:
import Ember from 'ember';
export default Ember.Controller.extend({
isBody: false,
actions: {
toggleBody() {
console.log("Look at me go!");
this.toggleProperty('isBody');
}
}
});
This is EmberCli environment, v2.0.0 and they say Controllers and Components will merge into one thing soon, so...

How to make Ember.js load RESTAdapter data before showing view?

I have a app with RestAdapter that takes proper data from server:
App.AFile= DS.Model.extend({
name: DS.attr( 'string' ),
...
App.Store = DS.Store.extend({
revision: 13,
adapter: DS.RESTAdapter.extend({url: "myapi"})
});
And a map like this:
App.Router.map(function() {
this.resource('allfiles', { path: '/allfiles' });
this.resource('onefile', {path: '/onefile/:onefile_id' });
And routes defined like this:
App.allfilesRoute = Ember.Route.extend({
model: function()
{
return App.AFile.find();
}
});
App.onefileRoute = Ember.Route.extend({
model : function(params)
{
return App.AFile.find(params.onefile_id);
}
});
And those templates:
<script type="text/x-handlebars" data-template-name="allfiles">
{{#each controller}}
{{#linkTo onefile this}}open{{/linkTo}}
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="onefile">
{{name}}
</script>
It works like this: user opens app and it displays allfiles template with a link called open. The link opens a template called onefile and passes the onefile_id to it.
When i open app and click open it works and displays proper name of one file. URL is set to #/onefile/1 where 1 is the onefile_id. So it works fine.
But when i refresh page (#/onefile/1) than name is not displayed anymore.
I've checked what is going on and in onefileRoute model function before i return the id and it occurs that App.AFile has null values for all fields defined. And after app loads those values are filled properly in the App.AFile object but are not displayed on the view.
So it looks like RestAdapter gets data after view display.
How to make it work?
App.onefileRoute = Ember.Route.extend({
model : function(params)
{
var m = App.AFile.find(params.onefile_id);
// at this point m might not be resolved, so name could be empty
return m;
},
afterModel: function(model, transition){
// at this point it should be resolved, what happens here?
console.log(model.get('name'));
}
});
My guess would be your endpoint is returning the wrong information for a model by id.

How does one "listen to the router" (respond to Router events in Views/Models) in Backbone.js?

In the Backbone.js documentation, in the entry for the Router.routes method, it is stated
When the visitor presses the back button, or enters a URL, and a particular route is matched,
the name of the action will be fired as an event, so that other objects can listen to the router,
and be notified.
I have attempted to implement this in this relatively simple example:
The relevant JS:
$(document).ready(function(){
// Thing model
window.Thing = Backbone.Model.extend({
defaults: {
text: 'THIS IS A THING'
}
});
// An individual Thing's View
window.ThingView = Backbone.View.extend({
el: '#thing',
initialize: function() {
this.on('route:showThing', this.anything);
},
anything: function() {
console.log("THIS DOESN'T WORK! WHY?");
},
render: function() {
$(this.el).html(_.template($('#thing-template').html(), {
text: this.model.get('text')
}));
return this;
}
});
// The Router for our App
window.ThingRouter = Backbone.Router.extend({
routes: {
"thing": "showThing"
},
showThing: function() {
console.log('THIS WORKS!');
}
});
// Modified from the code here (from Tim Branyen's boilerplate)
// http://stackoverflow.com/questions/9328513/backbone-js-and-pushstate
window.initializeRouter = function (router, root) {
Backbone.history.start({ pushState: true, root: root });
$(document).on('click', 'a:not([data-bypass])', function (evt) {
var href = $(this).attr('href');
var protocol = this.protocol + '//';
if (href.slice(protocol.length) !== protocol) {
evt.preventDefault();
router.navigate(href, true);
}
});
return router;
}
var myThingView = new ThingView({ model: new Thing() });
myThingView.render();
var myRouter = window.initializeRouter(new ThingRouter(), '/my/path/');
});
The relevant HTML:
<div id="thing"></div>
<!-- Thing Template -->
<script type="text/template" id="thing-template">
<a class='task' href="thing"><%= text %></a>
</script>
However, the router event referenced in the View's initialize function does not seem to get picked up (everything else works--I'm successfully calling the "showThing" method defined in the Router).
I believe I must have some misconception about what the documentation intended by this statement. Therefore, what I'm looking for in a response is: I'd love to have someone revise my code so that it works via a Router event getting picked up by the View, or, clearly explain what the Router documentation I listed above intends us to do, ideally with an alternative code sample (or using mine, modified).
Many thanks in advance for any assistance you can provide!
This is beacuse you are binding a listener to the wrong object. Try this in your View :
window.ThingView = Backbone.View.extend({
initialize: function() {
myRouter.on('route:showThing', this.anything);
},
...

Categories

Resources