Creating / Deleting User in Ember with Array Controller - ember.js

I am new to Ember and am trying to do a simple create / delete user. I am able to create a client, but can not delete them?
Client Controller:
export default Ember.ArrayController.extend({
actions: {
createClient: function(newName) {
// Create the new Todo model
var client = this.store.createRecord('client', {
name: newName,
avgMarkup: 2,
quotes: 1
});
// Clear the "New client" text field
this.set('newName', '');
// Save the new model
client.save();
}
}
});
I've then tried adding this:
destroyRecord: function() {
this.get('model').destroyRecord();
}
And I have no luck. My view is this:
<ul id="client-list">
<h6>Clients Name:</h6>
{{input type="text" id="new-client" placeholder="Please enter client name"
value=newName action="createClient"}}
{{#each}}
<li>
<input type="checkbox" class="toggle">
<label>{{name}}</label>
<button {{action "destroyRecord" }} class="destroy"></button>
</li>
{{/each}}
</ul>
Is this doable with an Array Controller?
Thanks

To remove the respective user just pass it to your destroyRecord action:
In your template pass thiswhich correspond to the current user being iterated:
<button {{action "destroyRecord" this}} class="destroy">Destroy</button>
And then when someone click in destroy button, model will be the current user:
destroyRecord: function(model) {
model.destroyRecord();
}

Related

How to save the endpoint data in model store if call is made from actions in controller

I have created a dialog box using the ember-modal-dialog. The content that is going to displayed in the dialog is received from the server. I am able to make the call to server and fetch the data. But I don't know how to save the data into my model store from actions.
Controller.js
actions:{
fiModal1: function(photo){
Ember.$('body').addClass('centered-modal-showing');
var currentState = this;
photo.toggleProperty('fidialogShowing'))
console.log('opendialog');
raw({
url: 'http://example.co.in/api/photo/'+photo.get('like_pk')+'/likes/',
type: 'GET',
}).then(function(result){
currentState.set('model.feed.liker',result)
});
},
bookmarked:function(liker){
liker.set('is_bookmarked',true)
},
}
feed.hbs
<p {{action "fiModal" photo }}>
{{photo.0.numlikes}}
</p>
{{#if photo.fidialogShowing}}
{{#modal-dialog translucentOverlay=true close = (action "fiDialogClose" photo)}}
{{#each model.feed.liker as |liker}}
<div class = "col-sm-6">
{{#if liker.is_bookmarked}}
<a href {{action "unbookmarked" liker}}>
<img class="foll" src = "images/button-bookmark-secondary-state-dark-b-g.png">
</a>
{{else}}
<a href {{action "bookmarked" liker}}>
<img class="foll" src = "images/button-bookmark.png">
</a>
{{/if}}
</div>
{{/each}}
Now the problem is that when action inside the dialog box is fired it throws an error:
fiver.set is not function
I think that the problem is occurring because I am not saving the result in the model store. How should I do it so the action inside the dialog box also works?
You can just encapsulate the results from your server into Ember.Object
Ember.Object.create(json)
For exemple replace your line
currentState.set('model.feed.liker',result)
by
currentState.set('model.feed.liker', result.map(function(item) {
return Ember.Object.create(item);
})
that way each elements inside your model.feed.liker should have a method 'set' available.

Embjers store.createRecord or store.push not updating view

I'm trying to create a new record and push it into the store. I can persist it just fine (and i'll push to the store after successfully persisting, once i figure this out), but the view/template isn't being refreshed. I know persistence works because, if I refresh the entire page, the new record appears.
I also tried this.store.push(), and nothing happens. I've looked around and everyone seems to be using filter() but only on a child set of records in a parent controller...
Thanks in advance, i have feeling its something really basic.
route/projects
export default Ember.Route.extend({
model: function(){
return this.store.find('projects');
}
});
controllers/projects
export default Ember.ArrayController.extend({
actions: {
createProject: function() {
var title = this.get('newProjectTitle');
var description = this.get('newProjectDescription');
if (!title.trim()) { return; }
// Create the new Project model
var project = this.store.createRecord('project', {
title: title,
description: description
});
project.save();
this.set('newProjectTitle', '');
this.set('newProjectDescription', '');
}
}
});
projects.hbs
<div class="form-group">
{{input type="text" class="form-control" placeholder="title" value=newProjectTitle}}
{{input type="text" class="form-control" placeholder="description" value=newProjectDescription action="createProject"}}
</div>
<button class="btn btn-xs btn-success" {{action 'createProject'}}>Create this Project</button>
<ul class="list-group">
{{#each project in model}}
{{#link-to 'project' project}}
<li class="list-group-item">
{{project.id}} - {{project.title}}
</li>
{{/link-to}}
{{/each}}
</ul>
You are missing the Setup Controller method -
setupController: function(controller, model) {
controller.set('model', model);
}
Use above method in route/projects.js file.
your code will be like -
export default Ember.Route.extend({
model: function(){
return this.store.find('projects');
}
setupController: function(controller, model) {
controller.set('model', model);
}
});
you can also refer this link for more information -
http://guides.emberjs.com/v1.10.0/routing/setting-up-a-controller/
ended up going with.. which works.. but is this the best way to do this?
var model = this.get('model');
model.pushObject(project);
I also found that...
var posts = this.store.find('post'); //network request.
var posts = this.store.all('post'); //no network request, but does live reload
Ember.js Models:Finding Reords

getting back reference to a specific model using Ember's Array Controller

I'm new to Ember and am finding some of their concepts a bit opaque. I have a app that manages inventory for a company. There is a screen that lists the entirety of their inventory and allows them to edit each inventory item. The text fields are disabled by default and I want to have an 'edit item' button that will set disabled / true to disabled / false. I have created the following which renders out correctly:
Inv.InventoryitemsRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON("/arc/v1/api/inventory_items/" + params.location_id);
}
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled="true"}}</p>
<p>{{input type="text" value=detail disabled="true"}}</p>
<button {{action "editInventoryItem" data-id=id}}>edit item</button>
<button {{action "saveInventoryItem" data-id=id}}>save item</button>
</div>
{{/each}}
</script>
So this renders in the UI fine but I am not sure how to access the specific model to change the text input from disabled/true to disabled/false. If I were just doing this as normal jQuery, I would add the id value of that specific model and place an id in the text input so that I could set the textfield. Based upon reading through docs, it seems like I would want a controller - would I want an ArrayController for this model instance or could Ember figure that out on its own?
I'm thinking I want to do something like the following but alerting the id give me undefined:
Inv.InventoryitemsController=Ember.ArrayController.extend({
isEditing: false,
actions: {
editInventoryItem: function(){
var model = this.get('model');
/*
^^^^
should this be a reference to that specific instance of a single model or the list of models provided by the InventoryitemsRoute
*/
alert('you want to edit this:' + model.id); // <-undefined
}
}
});
In the Ember docs, they use a playlist example (here: http://emberjs.com/guides/controllers/representing-multiple-models-with-arraycontroller/) like this:
App.SongsRoute = Ember.Route.extend({
setupController: function(controller, playlist) {
controller.set('model', playlist.get('songs'));
}
});
But this example is a bit confusing (for a couple of reasons) but in this particular case - how would I map their concept of playlist to me trying to edit a single inventory item?
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled="true"}}</p>
<p>{{input type="text" value=detail disabled="true"}}</p>
<button {{action "editInventoryItem" this}}>edit item</button>
<button {{action "saveInventoryItem" this}}>save item</button>
</div>
{{/each}}
</script>
and
actions: {
editInventoryItem: function(object){
alert('you want to edit this:' + object.id);
}
}
Is what you need. But let me explain in a bit more detail:
First of all, terminology: Your "model" is the entire object tied to your controller. When you call this.get('model') on an action within an array controller, you will receive the entire model, in this case an array of inventory items.
The {{#each}} handlebars tag iterates through a selected array (by default it uses your entire model as the selected array). While within the {{#each}} block helper, you can reference the specific object you are currently on by saying this. You could also name the iteration object instead of relying on a this declaration by typing {{#each thing in model}}, within which each object would be referenced as thing.
Lastly, your actions are capable of taking inputs. You can declare these inputs simply by giving the variable name after the action name. Above, I demonstrated this with {{action "saveInventoryItem" this}} which will pass this to the action saveInventoryItem. You also need to add an input parameter to that action in order for it to be accepted.
Ok, that's because as you said, you're just starting with Ember. I would probably do this:
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled=headerEnabled}}</p>
<p>{{input type="text" value=detail disabled=detailEnabled}}</p>
<button {{action "editInventoryItem"}}>edit item</button>
<button {{action "saveInventoryItem"}}>save item</button>
</div>
{{/each}}
</script>
with this, you need to define a headerEnabled property in the InventoryitemController(Note that it is singular, not the one that contains all the items), and the same for detailEnabled, and the actions, you can define them also either in the same controller or in the route:
App.InventoryitemController = Ember.ObjectController.extend({
headerEnabled: false,
detailEnabled: false,
actions: {
editInventoryItem: function() {
this.set('headerEnabled', true);
this.set('detailEnabled', true);
}
}
});
that's just an example how you can access the data, in case the same property will enable both text fields, then you only need one, instead of the two that I put . In case the 'each' loop doesn't pick up the right controller, just specify itemController.

How to remove an object from the controller when an Ember.Checkbox is checked

Currently I'm playing with the latest ember.js release and I'm building a simple "add username / remove username" hello world app. So far I can add a user (with the controller method below). I also have a checkbox in the html that when clicked should remove the user but ... right now I can only get the bool value of the checkbox to pass off. Instead I need the username to look it up and remove it from the controller content.
How can I re-do the html / view code below so that I can pass off the actual username instead of the bool value?
Thank you in advance!
PersonApp.ModifyPersonCheckbox = Em.Checkbox.extend({
change: function(event) {
PersonApp.personController.removePerson(this.$().val());
},
});
PersonApp.personController = Em.ArrayProxy.create({
content: [],
createPerson: function(username) {
var person = PersonApp.Person.create({ username: username });
this.pushObject(person);
},
removePerson: function(username) {
person = this.content.findProperty('username', username);
this.removeObject(person);
}
});
the basic html below shows how my checkedBinding is wired up
<ul>
{{#each PersonApp.personController}}
<li {{bindAttr class="isActive"}}>
<label>
{{view PersonApp.ModifyPersonCheckbox checkedBinding="isActive"}}
{{username}}
</label>
</li>
{{/each}}
</ul>
You will need to set the content on the view showing the checkbox so that when the event is triggered, the context is passed. I believe this will work:
{{view PersonApp.ModifyPersonCheckbox contentBinding="parentView.content" checkedBinding="isActive"}}
Then, the event variable in the change function will have a context variable containing the record associated with that checkbox. Then you won't even need to search for it in the controller. You can also just bind the username, but this way is cleaner.
The final solution looks like the below (notice the contentBinding="this" addition to the markup)
PersonApp.ModifyPersonCheckbox = Em.Checkbox.extend({
content: null,
change: function(event) {
PersonApp.personController.removePerson(this.content);
},
});
PersonApp.personController = Em.ArrayProxy.create({
content: [],
createPerson: function(username) {
var person = PersonApp.Person.create({ username: username });
this.pushObject(person);
},
removePerson: function(person) {
this.removeObject(person);
}
});
<ul>
{{#each PersonApp.personController}}
<li {{bindAttr class="isActive"}}>
<label>
{{view PersonApp.ModifyPersonCheckbox contentBinding="this" checkedBinding="isActive"}}
{{username}}
</label>
</li>
{{/each}}
</ul>

Rendering multiple Models each containing multiple objects in Ember Js

I'm quite new to EmberJS. I am trying to render a simple hasMany modelisation.
My app is supposed to handle multiple tasks for multiple persons.
First, I have models:
App.Task = Em.Object.extend({
name: null
});
App.Person = Em.Object.extend({
firstname: null,
lastname: null,
avatar: null,
tasks:null,
});
A person can have multiple tasks. So my personsController works like this:
App.personsController = Em.ArrayController.create({
content: [],
tasks:[],
addPerson: function(){
var aPerson = App.Person.create({
firstname: this.firstname,
lastname : this.lastname,
avatar : this.avatar,
});
this.pushObject( aPerson );
}
My tasksController, wich will handle tasks jobs:
App.tasksController = Em.ArrayController.create({
content:[],
contentBinding: "App.personsController.tasks",
name:'',
removeTask: function(e){
this.removeObject( e.context );
},
addTask: function(e){
this.pushObject( App.Task.create({"name":this.name}) );
}
});
contentBiding seems to be one of the keys here. I want it to auto-bind to the tasks of the person I'm working on.
On the views side, just working on my Handlebars templates:
<script type="text/x-handlebars">
{{view Em.TextField valueBinding="App.personsController.firstname" placeholder="firstname" }}
{{view Em.TextField valueBinding="App.personsController.lastname" placeholder="lastname" }}
<button {{action "addPerson" target="App.personsController"}} class="btn btn-primary" >Ajouter un developpeur</button>
{{#each App.personsController}}
<div>
<h3>{{firstname}}{{lastname}}</h3>
{{view Em.TextField valueBinding="App.tasksController.name"}}
<button {{action "addTask" target="App.tasksController"}} >Add a task</button>
{{#each App.tasksController}}
{{view Em.TextField valueBinding="name" }}
<button {{action "removeTask" target="App.tasksController"}} >x</button>
{{/each}}
</div>
{{/each}}
</script>
So, when I'm adding a new person, everything works fine. But if I add a task, the task is added on each of the person's tasks in the view.
I'm afraid I'm making a conceptual mistake, and I can't find a good documentation about this kind of visualisation. I've seen examples of hasMany relations with ember.data, but I'd like first to understand properly what is going on here.
Your addTask function adds a new task to the array maintained within App.tasksController, but there is nothing binding these tasks to any instance of App.Person.tasks.
I suggest creating new View class with a binding to your tasksController and to a single App.Person instance. The personBinding of this view would be set inside of your outer {{#each}} loop. Have this view be responsible for rendering App.Person.tasks for a single person.
Change addTask in your controller to accept a reference to an App.Person as an argument, then add the task explicitly to that person's tasks array in the body of the function.