Model reloading with Ember Data - javascript

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"}).

Related

Using this.transitionTo to change query params gives error

Using pretty much copy paste from Ember.js docs
App.CresShowResultController = Ember.ArrayController.extend({
queryParams: ['county'],
county: null,
actions: {
displayQueryData: function(){
this.transitionTo({queryParams: {county: 'someCounty'}});
},
},
});
The action is called from another controller after a form is analysed.
I get an error: Uncaught TypeError: undefined is not a function
Here is the route as well.
App.CresShowResultRoute = Ember.Route.extend({
renderTemplate: function(){
this.render('showResult');
}
});
SideQuestion: How can I use transitionTo to change URL parameters straight from another controller without using the action "displayUseryData" as middleman function?
EDIT: Added my Router.map to specify:
App.Router.map(function(){
this.resource('cres', function() {
this.route('showResult');
});
this.resource('about');
this.resource('posts', function() {
//child route posted inside the parent
this.resource('post', { path: ':post_id'});
});
});
Like always, thank you for any helping comments!
try:
App.CresShowResultController = Ember.ArrayController.extend({
queryParams: ['county'],
county: null,
actions: {
displayQueryData: function(){
this.transitionTo({queryParams: {county: 'someCounty'}});
}.bind(this),
},
});
I think that "this" in the displayQueryData function is a window reference.
In the case you reference above, just updating the queryParam itself will have the effect you are looking for.
In the route, you can define if these queryParams will replace the url, or if it will refresh the model.
Use the transitionToRoute, when you wish to switch to a different route, or different model.
App.CresShowResultController = Ember.ArrayController.extend({
queryParams: ['county'],
county: null,
actions: {
displayQueryData: function(){
this.set('county', 'someCounty');
// this.transitionTo({queryParams: {county: 'someCounty'}});
},
},
});

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');
}
});

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...

ember.js - define route with optional parameter and default model

I want to define a route in emberjs, that has an optional parameter
eg:
/video
and
/video/123
if no parameter is supplied, I want to use a default model/fixture.
if a parameter is supplied, then I want to obviously lookup the model using the parameter.
if I then go to a different route, and return to the route without the parameter, I want to use the previously loaded model.
eg:
startup app
/video - shows my default/fixture model
/video/123 - shows model 123
/another-route - shows new route
/video - shows model 123
is this possible?
I ended up using a different solution:
this.resource('video', function() {
this.route('index', {path: '/'});
this.route('item', {path: ':id'});
});
These routes support:
/video - shows my default/fixture model
/video/123 - shows model 123
When the user access to /video, the VideoIndexRoute must redirect to VideoItemRoute without any id.
var VideoIndexRoute = Em.Route.extend({
afterModel: function() {
// this is the tricky part
this.replaceWith('video.item', '');
}
});
Now, the VideoItemRoute must check if there is any model associated, and when it is missing, it should use the default fixtures or a new one.
var VideoItemRoute = Em.Route.extend({
model: function(param) {
if (param.id) {
return this.store.find('video', param.id);
}
},
setupController: function (controller, model) {
if (!model) {
model = this.store.createRecord('video',{
name: 'default Name'
});
// or use fixture...
}
this._super(controller, model);
}
});
There is a clean way to do this, although it is slightly "tricky". The idea is to use a nested route to hold the id, but not render it, instead having the parent route be responsible for rendering it using the render helper. When you do it this way, all the logic can live in VideoChoiceController, and it will be used for displaying either the default video or a specific one. When doing it this way, there is no need to explicitly "remember" the last video, the state machine that the route engine represents does it for you.
App.Router.map(function) {
this.resource('video', function(){
this.route('choice', {path: ':video_id'});
});
});
App.VideoRoute = Ember.Route.extend({
model: function(params) {
return App.get('defaultVideo');
},
setupController: function(controller, model) {
var video_choice = this.controllerFor('video.choice')
// this is necessary if you want, for example,
// to display the name or a link to the default video
// when a specific video is being displayed
controller.set('model', model);
if(Ember.isEmpty(video_choice.get('model'))){
video_choice.set('model', model);
}
}
});
App.VideoChoiceRoute = Ember.Route.extend({
model: function(params) {
return this.get('store').find('video', params.video_id);
},
renderTemplate: function() {
// if you don't override renderTemplate to do nothing,
// everything will still work but you will get an assertion
// error that render should only be used once with a
// singleton controller
}
});
<script type="text/x-handlebars">
<div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name='video'>
<div> attrributes here always refer to the default video: {{name}} </div>
{{render "video.choice"}}
</script>
<script type="text/x-handlebars" data-template-name='video'>
<div>
attrributes here always refer to specific or last video,
or default if a specific video has never been loaded: {{name}}
</div>
</script>
Definitely, you'll have to do something a little funky, like storing the last video in some global variable, but that's up to you.
http://emberjs.jsbin.com/uhoQozu/1/edit
http://emberjs.jsbin.com/uhoQozu/1#/video
http://emberjs.jsbin.com/uhoQozu/1#/video/32
App.Router.map(function() {
this.resource('videoModel', {path:'/video/:video_id'});
this.resource('video'); // this resource can be accessed at /video
});

Live Sorting or Fitering a Model using Textbox in Ember

I was watching Ember screencasts & stumbled upon autocomplete-widget. I tried to implement something like that but it's not working it seems.
I am getting data using $.getJSON and I want to filter that using textbox.
Here's what I have tried,
App = Ember.Application.create();
App.Model = Ember.Object.extend({
});
App.IndexRoute = Ember.Route.extend({
redirect : function() {
this.transitionTo('users');
}
});
App.UsersController = Ember.ArrayController.extend({
filteredContent : function() {
var searchText = this.get('searchText'), regex = new RegExp(searchText, 'i');
return this.get('model').filter(function(item) {
return regex.test(item.name);
});
}.property('searchText', 'model')
});
App.Users = App.Model.extend({
id : "",
name : ""
});
App.UsersRoute = Ember.Route.extend({
model : function() {
return App.Users.findAll();
},
setupController : function(controller, model) {
controller.set('model', model);
}
});
App.Users.reopenClass({
findAll : function() {
return $.getJSON("user.php", function(data) {
return data.map(function(row) {
return App.Users.create(row);
});
});
}
});
App.Router.map(function() {
this.resource("users", {
path : "/users"
});
});
Here's my HTML,
<body>
<script type="text/x-handlebars" data-template-name="users">
{{view Ember.TextField value=searchText}}
<button {{action last}}>filter</button>
<button {{action refresh}}>refresh</button>
{{#each item in content }}
<tr><td>
<p> {{item.name}}</p>
</td></tr>
{{/each}}
</script>
<script type="text/x-handlebars">
<h1>Application Template</h1>
{{outlet}}
</script>
</body>
I am actually stuck on where should I make changes, I just need some pointers.
Update: Even though I am getting the expected outcome but I am getting
Uncaught TypeError: Cannot read property 'selectedIndex' of undefined
Any idea why I am getting this?
I think that you are returning before the promise from $.getJSON has been fulfilled. Try changing your App.User.findAll so that it returns the results from inside the success callback. So specifically, your findAll implementation might look like:
App.Users.reopenClass({
findAll: function() {
return $.getJSON("https://api.github.com/users/rjackson/repos", function(data) {
return data.map(function(row) { return App.Users.create(row); });
});
}
});
Also, I do not believe that you need to manually create the ArrayProxy object. Return an array from your routes model hook should suffice.
I made some additional tweaks to your original (including using a sample JSON endpoint) here: http://jsbin.com/oWUBeMu/3/edit
Updated: 2013/08/30
The selectedIndex error is being caused by the HTML comments in your 'users' template. Handlebars comments should be {{! }} or {{!-- --}}. The html comments were causing some bizare escaping when parsing the template that caused it not to be able to bind to the properties properly.

Categories

Resources