i am new to emberjs and i am trying to iterate through arr and render a table with the content of elements of the array the each loop renders <!----> instead of rows in the table
what am i doing wrong?
here is my code:
app.js
arr=[{id:1,name:foo,completed:'yes'},{id:2,name:'bar', completed:'no'}]
App= Ember.Application.create();
App.Router.map(function(){
})
App.IndexRoute=Ember.Route.extend({
model: function(){
return arr;
}
})
App.SingleTaskComponent = Ember.Component.extend({
templateName: "components/single-task",
tagName: ""
});
App.TasksCollectionComponent = Ember.Component.extend({
templateName: "components/tasks-collection",
tagName: "tbody",
actions: {
newTask: function(){
console.log("here");
}
}
});
and here is the hbs code:
<script type="text/x-handlebars" id="components/single-task">
<tr {{bind-attr id=id}}>
<td>
<input type="text" name="task" {{bind-attr value=name}} >
</td>
<td>
<input type="checkbox" name="completed">
</td>
</tr>
</script>
<script type="text/x-handlebars" id="components/tasks-collection">
<tr>
<td><button>+</button></td>
<td>Tasks</td>
</tr>
{{#each model as |task|}}
{{single-task id=task.id name=task.name completed=task.completed}}
{{/each}}
</script>
<script type="text/x-handlebars" id="index">
<table>
{{tasks-collection}}
</table>
</script>
Your coding looks like you are not using ember-cli. please use it. In this link you can go through enormous projects which are using ember, you can learn from them how are they using it. You can even play with ember-twiddle for easy learning. I will encourage you to follow ember guides tutorial.
Regarding your question,
You need to pass the required data to components,
{{tasks-collection model=model}}
In single-task component, you can avoid bind-attr instead you can use it like
<tr id={{id}}>
Refer deprecation guide bind-attr for more details
Related
I am very new to Ember js. when i route one template to another it working properly.but the problem is when i was render same template it won't work.
My code is follows:
index.html:Manager template in index.html
<script type="text/x-handlebars" data-template-name="manager">
{{#each model.manager}}
<div class="pure-g-r content-ribbon">
<div class="pure-u-1-3">
<div class="img-viewer-profile">
<img {{bindAttr src="image"}}>
</div>
</div>
<div class="pure-u-2-3">
<div class="l-box">
<h4 class="content-subhead">{{name}}</h4>
<table class="pure-table">
<tbody>
<tr class="pure-table-odd">
<td>Id</td>
<td><b>ATL-{{id}}</b></td>
</tr>
<tr class="pure-table-odd">
<td>Team</td>
<td><b>{{team}}</b></td>
</tr>
<tr>
<td>Division</td>
<td><b>{{division}}</b></br>
</tr>
<tr class="pure-table-odd">
<td>Manager</td>
<td>
<b>
<a href="#" {{action "managerinfo" manager_id}}>
{{manager_name}}
</a>
</b>
</td>
</tr>
{{/each}}
<tr>
<td>Reportees</td>
<td>
{{#each model.results}}
<br><b>
<a href="#" {{action "profileinfo" id}}>
{{reportees}}
</a>
</b></br>
{{/each}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{{outlet}}
</script>
app.js:
=========
App.ManagerController = Ember.ObjectController.extend({
manager_id: '',
id: '',
actions:{
managerinfo: function(manager_id) {
// the manager id of selected manager field
var manager_id = manager_id;
alert("profile");
alert(manager_id);
managerdata = $.ajax({
dataType: "json",
url: "/manager?manager_id=" + manager_id,
async: false}).responseJSON
managerdata.manger_id = manager_id;
console.log(managerdata);
this.transitionToRoute('manager', managerdata);
}
)}
Now my problem is when render the new manager data to manager it wont be displayed.
After refresh only it shows the data.
what mistake i was done in this code , i dont understand.so please provide me solution.
i added my complete code here with proper tags order.
As per your comment, the way you are doing is not suggested. You can pass manager_id in the route url. I will give you very basic skeleton which you can make further changes. Do remember, if you want to set model data from ajax, use model hook in the route
First Router
App.Router.map(function() {
this.resource("managers", function(){
this.route("all");
this.route("manager", { path: "/:manager_id" });
});
});
So here with #/manager/all displays all managers list
#/manager/:manager_id displays manager with id manager_id
Next ManagerAll route
App.ManagersAllRoute = Ember.Route.extend({
model: function() {
//do ajax and return managers data which sets as model for this route
}
});
sameway
App.ManagersManagerRoute = Ember.Route.extend({
model: function(params) {
//do ajax and return managers data which sets as model for this route
//here params will have the manager_id passed through url
//as it is ajax, create a promise
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
dataType: "json",
url: "/manager?manager_id=" + params.manager_id,
async: false}).then(function(data){
resolve(data);
})
});
}
});
Next is template for managers
{{#each model.manager}}
{{#link-to 'managers.manager' manager_id}}{{{manager_name}}{{/link-to}}
{{/each}}
Now a template for manager
{{manager_id}}
{{manager_name}} blah blah blah
You didn't close the each tag properly.
<script type="text/x-handlebars" data-template-name="manager">
{{#each model.manager}}
<a href="#" {{action "managerinfo" manager_id}}>
{{manager_name}}
</a>
{{/each}}
</script>
Also you haven't closed the ManagerController correctly in the given above. Double check that.
App.ManagerController = Ember.ObjectController.extend({
manager_id: '',
id: '',
actions:{
managerinfo: function(manager_id) {
// the manager id of selected manager field
var self=this;
var manager_id = manager_id;
alert("profile");
alert(manager_id);
managerdata = $.ajax({
dataType: "json",
url: "/manager?manager_id=" + self.manager_id,
async: false}).responseJSON.then(function(managerdata) {
managerdata.manger_id = self.manager_id;
console.log(managerdata);
this.transitionToRoute('manager', managerdata);
})
}
)}
I'm currently learning EmberJS as I feel single page apps using a JS framework and consuming a backend API are the way things are going to be moving. I've recently learned Laravel without any particular problem, but I'm finding Ember remarkably difficult.
Most of my issues I've worked through, but I'm having one that I don't even know how to debug.
Essentially, my interface displays a list of clients. Clicking on a name goes to that client. All of this is connected to a PHP/Laravel based API, which is working entirely fine and in the right format. Data is not the problem here.
That said, I should point out that my data does not have an "id" strictly, but connects using something more like a guid: 912ec803b2 instead of 231. The API is built to handle that, and it's a requirement. It also means there is no "id" in the data, but there is a "hash" which may potentially be confusing ember in some way?
This basic functionality just doesn't seem to work correctly. When a user clicks the Client link, it does navigate to the client. But it's adding a blank row to the clients list page, then going to the client page. Returning to the clients page shows the extra blank row, and the same thing will recur if clicked again.
Checking the Ember inspector in Chrome shows the data collection increasing, with blank data being added. I'm not sure why.
I've posted the code here. This should be all that's necessary. Is this behaviour a common trap for young players, of have I done something unusual?
Apologies for the length, just didn't want to omit something relevant.
// app.js
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function() {
this.resource('clients', function() {
this.route('new');
});
this.resource('client', { path: 'clients/:client_hash' }, function(){
});
});
App.Store = DS.Store.extend({
url: 'http://myclientinfo'
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
App.Client = DS.Model.extend({
name: DS.attr('string'),
hash: DS.attr('string')
});
App.ClientsRoute = Ember.Route.extend({
model: function(){
return this.store.find('client');
}
});
App.ClientIndexRoute = Ember.Route.extend({
model: function(params){
return this.store.find('client', params.client_hash);
}
});
// templates
<script type="text/x-handlebars">
<div class="container">
<ul class="nav nav-pills">
<li>{{#link-to 'clients'}}Clients{{/link-to}}</li>
</ul>
{{outlet }}
</div>
</script>
<script type="text/x-handlebars" id="client">
client outer
{{outlet}}
</script>
<script type="text/x-handlebars" id="clients">
client outer
{{outlet}}
</script>
<script type="text/x-handlebars" id="client/index">
client index
<h1>{{name}}</h1>
</script>
<script type="text/x-handlebars" id="clients/index">
<div class="row">
<div class="col-md-12 col-lg-12">
<h1>All Clients</h1>
</div>
</div>
<div class="row"><div class="col-md-12 col-lg-12">
{{#link-to 'clients.new' class="btn btn-info add-btn"}}
<i class="fa fa-plus"> Add new client</i>
{{/link-to}}
</div></div>
<div class="row">
<div class="col-md-12 col-lg-12">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
{{#each item in model}}
<tr>
<td>{{#link-to 'client' item.hash}}{{item.name}}{{/link-to}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</script>
Ok, just following this up since I've sorta kinda fixed it.
this.resource('client', { path: 'clients/:client_hash' }, function(){
This line did more than I thought. I thought it was more of a defining placeholder, like in Laravel.
Route::get('user/{id}', function($id)
The name used, whether it's {id} or {hash} or {poopypants} doesn't matter because it's being defined and used at that time.
I changed it to this:
this.resource('client', { path: 'clients/:client_id' }, function(){
That lets the default link-to helpers work, rather than simply getting "undefined" like they were for everything else I tried. The name of that segment is actually meaningful, it is used to derive the actual values for the segment.
With this done I was able to refactor the loop code slightly, fixing the helper.
{{#each item in model}}
<tr>
<td>{{#link-to 'client' item}}{{item.name}}{{/link-to}}</td>
This could also be refactored down more.
{{#each}}
<tr>
<td>{{#link-to 'client' this}}{{name}}{{/link-to}}</td>
Note that {{#link-to 'client' this}} works, while {{#link-to 'client' this.id}} mostly works, but gets the bug stated in the OP. A bug that I believe has taken me three DAYS to fix.
I'd like to sort an Array or users which gets fetched by ember-data. I can't figure out to sort the array be lastName. The following code doesn't do the job. How can I fix it?
app.js
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UsersController = Ember.ArrayController.extend({
sortProperties: ['lastName'],
sortAscending: true
})
index.html
<script type="text/x-handlebars" data-template-name="users">
<table class='table table-striped'>
{{#each model itemController="user"}}
<tr>
<td>{{lastName}}</td>
</tr>
{{/each}}
</table>
</script>
Kudos to Bradley Priest for answering the question. Using this in the template does the trick.
index.html
<script type="text/x-handlebars" data-template-name="users">
<table class='table table-striped'>
{{#each this itemController="user"}}
<tr>
<td>{{lastName}}</td>
</tr>
{{/each}}
</table>
</script>
I'm trying to add objects to my Emberjs Arraycontroller. I have a "create" action that fires when a button is pushed. This works fine but I can't seem to add the element with the this.pushObject function to the ArrayController. I get this error message:
Uncaught Error: The result of a server query (on App.Software) is immutable.
I guess this is because I'm using the RESTAdapter to load data and it does not like that I'm adding elements manually?
Here is my controller and the create action.
App.SoftwareIndexController = Ember.ArrayController.extend({
sortProperties: ['revision'],
create:function(){
var revision = $('#software_revision').val();
var doc = $('#software_document').val();
var software = App.Software.createRecord({
product_id: 1,
revision: revision,
doc: doc
});
this.pushObject(software);
}
});
Here is the route
App.SoftwareIndexRoute = Ember.Route.extend({
setupController:function(controller){
var product_id = 1;
controller.set('content', App.Software.find({product_id:1}));
}
});
Here is the model and store
App.Store = DS.Store.extend({
revision: 12,
adapter: 'DS.RESTAdapter'
});
DS.RESTAdapter.configure("plurals", {
software: "software"
});
App.Software = DS.Model.extend({
revision: DS.attr('string'),
doc: DS.attr('string'),
verified: DS.attr('boolean')
});
And here is the template view with the create form and list of software
<script type="text/x-handlebars" data-template-name="software/index">
<p>
<fieldset>
<legend>Create a new software revision</legend>
<label for="software_revision">Revision</label>
<input id="software_revision" name="software_revision" type="text" placeholder="">
<label for="software_document">Document ID</label>
<input id="software_document" name="software_document" type="text" placeholder="">
<button class="btn btn-success" {{action create}}>Create</button>
</fieldset>
</p>
{{#if length}}
<table class="table">
<thead>
<tr>
<th>Revision</th>
<th>Created</th>
</tr>
</thead>
<tbody>
{{#each controller}}
<tr>
<td>{{revision}}</td>
<td>{{createdAt}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<div class="alert alert-info">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>No software revisions found!</strong> start by creating a new revision above.
</div>
{{/if}}
</script>
Does anybody know the proper way to add new object to a ArrayController store? Thank you!
This works by the way if I change the route so it doesn't use the RESTAdapter
App.SoftwareIndexRoute = Ember.Route.extend({
setupController:function(controller){
var product_id = 1;
controller.set('content', []); // not using the RESTAdapter to load data
}
});
I had this same problem. It looks like the content returned from App.Software.find() is an immutable array. I was able to get around this by getting the content of the immutable array which returned a mutable array.
For example:
In ember 1.0.0 + ember data 1.0.0 beta 3:
this.store.find('software').then(function (softwares) {
controller.set('content', softwares.get('content'));
});
And this is only a guess but for the version you were working with at the time of your post:
controller.set('content', App.Software.find().get('content'));
<script type="text/x-handlebars" data-template-name="item-view">
{{#with view.content.json}}
<tr>
<td>{{unbound artistName}}</td>
<td>{{unbound price}}</td>
<td>{{unbound primaryGenreName}}</td>
<td>{{unbound version}}</td>
</tr>
{{/with}}
</script>
<table>
<script type="text/x-handlebars">
{{view Em.CollectionView itemViewClass="App.ItemView" contentBinding="App.itemsController"}}
</script>
</table>
The HTML table tags in the above template are stripped out using ember-1.0.pre.js. Is there a more appropriate pattern than this for outputting a table of results where there are many values?
The post Handlebars.js: Nested templates strip “safe” HTML appears relevant to the subject of preserving the tags but Ember adds its own abstraction on top of this.
Looking at the ember docs, I think this what you are trying to find. You should be able to substitute a bunch of different list types in depending on your goal.
anUndorderedListView = Ember.CollectionView.create({
tagName: 'tbody',
content: ['A','B','C','D'],
itemViewClass: Ember.View.extend({
templateName: 'item-view'
})
});
DEMO