I have a template where I represent a User which hasMany usertags. The values are there after I hit F5, I'm not sure how to automatically refresh the view. I've looked into the ember observer, but it only fires after the DOM load - anyway I'm not sure if observers are the answer yet so looking for a fresh opinion on how to do this.
{{username}}
<span {{action 'addusertag' selectedTag}}>Add</span>
{{#each tag in model.usertags}}
{{/each}}
App.UserRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controller.set('model', this.get('store').find('user',model.id));
},
actions: {
addusertag: function(params){
var tag = this.get('store').createRecord('usertag', {tag_id: params.id, user_id: this.currentModel.id});
tag.save();
}
}
});
Thanks!
Check out this answer.
After you save, you want to add your usertag to the user.usertags array.
addusertag: function(params){
var context = this;
var tag = this.get('store').createRecord('usertag', {tag_id: params.id, user_id: this.currentModel.id});
tag.save().then(function (tag) {
context.controller.get('content.usertags').pushObject(tag);
});
}
Related
I want to implement simple ember app, where I have a search dialog, a list of results and a detailed view if I click on the results, something like this:
http://jsbin.com/tuyapabuhe/2/edit
The search method of the IndexController is doing an ajax request to populate the model, but I'm not sure if that is the best way to do it. I specially don't like the var self = this; part. Is there an ember way to do that search?
EDIT
I updated the example, now is doing an ajax request and is more realistic:
http://jsbin.com/wimogu/4/edit
The ajax call should be happening inside the model hook for the Index route. Instead of observes you can just use a property as follows:
App.IndexRoute = Ember.Route.extend({
model: function(){
return data; // your ajax call here...
}
});
App.IndexController = Ember.ArrayController.extend({
filtered: function() {
var name = this.get('name') || '';
var people = data.filter(function(el){
if(el.name.toLowerCase().indexOf(name)>-1)
return el;
});
return people;
}.property('name', 'model')
});
Then, in your template you can just do
{{#each user in filtered}}
{{#link-to 'person' user.id}}
<div>{{user.name}}</div>
{{/link-to}}
<hr/>
{{/each}}
Working solution here
Per my comment on another answer, I would suggest the following for AJAX calls based on one or more filters, complete with debouncing to limit the number of requests:
function handleSearch() {
this.set('model', this.store.find('user', this.get('query')));
}
App.IndexController = Ember.Controller.extend({
search: '',
sort: 'first_name',
direction: 'asc',
query: function() {
return {
search: this.get('search'),
sort: this.get('sort'),
direction: this.get('direction')
};
}.property('search'),
queryDidChange: function() {
Ember.run.debounce(this, handleSearch, 200);
}.observes('query').on('init'),
actions: {
clearSearch: function() {
this.set('search', '');
}
}
});
I have this running in the wild right now and it works perfectly.
ive searched for this and have not found an answer. I have 2 routes: "Index", which creates/updates an expense list, and "Charts", which charts the values of the expenses.
In order to handle the expense charts, I have the following function:
getData: function() {
var expenses = this.store.all('expense');
expenses.update();
var retarr = Ember.A();
expenses.forEach(function(expense) {
retarr.pushObject({
label: expense.get('name'),
value: expense.get('amount'),
group: 'expense'
});
});
return retarr;
}.property()
This is then passed to the ember-charts component in the Charts route.
<script type="text/x-handlebars" id='charts'>
<div class="chart-container">
{{horizontal-bar-chart data=getData}}
</div>
However, if I create/delete an expense in the "Index" route and hten transition to the "Charts" route, the DS.RecordArray doesn't update despite calling the "update()" function. As such, the chart does not reflect the created/deleted changes until the page is refreshed.
How do I fix this so the RecordArray auto updates along with the chart? I've broken my head for over two days trying different things. Thanks!
Your property getData should be bound to anything, if this something is an array you should use #each. For example as you can see here:
remaining: function() {
var todos = this.get('todos');
return todos.filterBy('isDone', false).get('length');
}.property('todos.#each.isDone')
I suggest you another approch, let's modify your model:
App.Chart = DS.Model.extend({
// fieds here...
label: function() {
return this.get("name");
}.property("name"),
value: function() {
return this.get("amount");
}.property("amount"),
group: function() {
return "expense";
}.property(),
)};
In your route set myCharts property:
App.ChartRoute = Ember.Route.extend({
setupController: function(controller, model) {
this._super(controller, model);
var charts = this.store.find("chart");
controller.set("myCharts", charts);
}
});
Then you could use your horizontal chart:
<div class="chart-container">
{{horizontal-bar-chart data=myCharts}}
</div>
Note: I didn't tested this code but it should work
i am trying to build my first emberjs app and i wonder how i can save the state of a nested route to rebuild that state when the top route is revisted in the current session.
To give an example:
Lets Say a user switches from /overview/item1 to /info and then returns to
/overview/ and want to redirect him to /overview/item1
HTML
<div id="navigation">
{{#link-to 'info' class='link' }}Info{{/link-to}}
{{#link-to 'overview' class='link'}} Overview {{/link-to}}
</div>
JS
App.Router.map(function(){
this.route('info');
this.resource('overview', function () {
this.resource('item', { path : '/:item_id'});
});
});
it would be really nice if somebody could give me a hint to the right approach of this.
There are various ways for achieving your goal. Basically, you need to store state of last visited overview/:item_id route in the parent route or controller. Then, you need to check this state before resolving model of overview route. If state is not null (user was selected some item from overview/:item_id), abort current transition and start the new one (to
overview/:selected_item_id).
Schematic solution in code:
// 1st approach
App.OverviewController = Ember.ObjectController.extend({
selectedItem: null
});
App.OverviewRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (this.get('controller.selectedItem')) {
transition.abort();
this.transitionTo('overview.item', this.get('selectedItem'));
}
}
});
App.OverviewItemRoute = Ember.Route.extend({
afterModel: function(model) {
this.controllerFor('overview').set('selectedItem', model);
}
});
// 2nd approach (less code)
App.OverviewRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (this.get('controller.selectedItem')) {
transition.abort();
this.transitionTo('overview.item', this.get('selectedItem'));
}
},
setupController: function(controller) {
controller.reopen({ selectedItem: null });
}
});
App.OverviewItemRoute = Ember.Route.extend({
afterModel: function(model) {
this.controllerFor('overview').set('selectedItem', model);
}
});
It's important to keep the item itself, not it's id, because it'll way more easier to load overview/:item_id route in the future (passing stored model in this.transitionTo('overview.item', item)).
I'm using Ember App Kit. I have a form that takes a student name and I can save the data into a database without any problem. The problem is the data (student name) retains on the form whenever I get transition back to this route (http://localhost:8000/#/students/new) from another page. If I refresh the screen, then the data will be cleared out and I will get a fresh form. What am I doing wrong?
Also, if I decide not to save or add the record and go to see the list of students, I see an empty record on screen. That record is not in the database though. How can I prevent that?
//--------------------------------------------
// Controller
var StudentsNewController = Ember.ObjectController.extend({
init: function() {
var newSystem = this.store.createRecord('student');
this.set('newStudent', newStudent);
this._super();
},
actions: {
acceptChanges: function () {
var self = this;
self.get('newStudent').save().then(function(student){
self.transitionToRoute('students');
});
}
}
});
export default StudentsNewController;
//--------------------------------------------
// Model
var Student = DS.Model.extend({
name: DS.attr('string'),
major: DS.belongsTo('major')
});
export default Student;
//--------------------------------------------
// Template
<form {{action 'updateSystem' on="submit"}}>
<fieldset>
<div>
<label>Student Name</label>
{{input value=newStudent.name size="50"}}
</div>
<button {{action 'acceptChanges'}}>Add</button>
</fieldset>
</form>
Try to setup the controller in you route (here) instead of using the init method in the controller. It's one of the routes responsibilities.
I think the problem is that you assume that every time you transition to the StudentsNewRoute a new StudentsNewController is created, and thus the init method is called.
The truth is Ember creates the controller once and changes it's content based on the model and the setupController hooks. So the init method of the controller it's called once and you end up with the same record every time you transition to the route.
To solve this you'd do something like this:
var StudentsNewController = Ember.ObjectController.extend({
newStudent: null,
actions: {
acceptChanges: function () {
this.get('newStudent').save().then((student) => {
this.transitionToRoute('students');
});
}
}
});
//--------------------------------------------
var StudentsNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('student');
},
setupController: function(controller, model) {
controller.set('newStudent', model);
},
});
I hope this helps you!
actions: {
acceptChanges: function () {
var self = this;
self.get('newStudent').save().then(function(student){
self.set('newStudent','');
self.transitionToRoute('students');
});
}
}
I'm evaluating Emberjs in the context of whether we could port some of our code to it but maintain the same api so my first day really looking at it.
I'm using the Tom Dale tutorial but WITHOUT ember-data. I think I have kinda figured out how to get data into the app (thx #kingping2k). I just need to get this to save / update.
I have a doneEditing action which gets called when I click on it as seen by console but how do I get a reference to the model. Looking at the controller docs (http://emberjs.com/api/classes/Ember.Controller.html), I don't see a really obvious property like model or something. How would I tell the PostController to save the post that it is getting back in its route? Also, do people normally use jQuery promises to do something else after the save has completed here(I'm assuming yes)?
I've included the relevant code with the doneEditing action at the bottom where I'm looking for help:
thx for any help
Model:
Hex.Post = Ember.Object.extend({
id: null,
body: null,
isEnabled: null,
createdAt: null,
save: function(data){
console.log("you want to save this item");
$.post( "api/post", data, function( data ) {
// something here
});
}
});
View:
<script type="text/x-handlebars" id="post">
{{#if isEditing}}
{{partial 'post/edit'}}
<button {{action 'doneEditing'}}>Done</button>
{{else}}
<button {{action 'edit'}}>Edit</button>
{{/if}}
<h1>{{id}}</h1>
{{outlet}}
</script>
Route:
Hex.PostRoute = Ember.Route.extend({
model: function(params) {
console.log('called with: ' + params.post_id);
return Hex.Post.findById(params.post_id);
}
});
Controller:
Hex.PostController = Ember.ObjectController.extend({
isEditing: false,
actions:{
edit: function() {
this.set('isEditing', true);
},
doneEditing: function() {
this.set('isEditing', false);
console.log("this gets called");
//this.get('content').save();
//this.save();
//console.log("here: " + this.model.id);
//this.model.save(); //doesn't work ???
// this.post.save(); //doesn't work ???
//this.get('store').commit(); // prob no
}
}
});
when you return a model from the model hook it's then passed to the setupController in the route. The default implementation of setupController does this, controller.set('model', model)
setupController:function(controller, model){
controller.set('model', model');
}
so to get the model within the context of the controller just get that property.
var model = this.get('model')
I would return the promise, then you can trigger something on save/failure etc
save: function(){
console.log("you want to save this item");
return Ember.$.post( "api/post", JSON.stringify(this));
}
doneEditing: function() {
this.set('isEditing', false);
var model = this.get('model');
model.save().then(function(){alert('saved');},
function(){alert('failure');});
}
And generally you'll put save in the reopen
Hex.Post.reopen({
save: function(){
console.log("you want to save this item");
return Ember.$.post( "api/post", JSON.stringify(this));
}
});