Using ember 1.0.0-pre3
I have a little app that has this code:
window.App = Ember.Application.create()
App.ApplicationController = Ember.Controller.extend({})
App.Router.reopen
location: 'history'
App.Router.map ->
#resource 'users', ->
#route 'new'
App.IndexRoute = Ember.Route.extend
renderTemplate: ->
#render('index')
This is application.hbs in the templates directory:
<div class='navbar navbar-inverse navbar-fixed-top'>
<div class='navbar-inner'>
<div class='container'>
<div class='nav-collapse collapse'>
<ul class='nav'>
<li>{{#linkTo 'index'}}Home{{/linkTo}}</li>
<li>{{#linkTo 'users.index'}}Users{{/linkTo}}</li>
</ul>
</div>
</div>
</div>
</div>
<div class='container' id='main'>
<div class='content'>
<div class='row'>
<div class='span12'>
<div class='page-header'></div>
{{outlet}}
</div>
</div>
</div>
</div>
The problem is that it doesn't render this template. It doesn't throw an error when loading the the app at the base url "http://127.0.0.1:3000/". It will throw an error if I try an undefined route, so I know that Ember is loaded.
There does not appear to be anything wrong with your ember code. I made a copy on jsbin and it works fine: http://jsbin.com/ipivoz/1/edit
Pretty sure that means your template is not being compiled. To be sure, try adding the following to your application ready hook:
window.App = Ember.Application.create({
ready: function() {
console.log("Ember.TEMPLATES: ", Ember.TEMPLATES);
}
});
Ember expects compiled handlebars templates to be in this array. If you run the above jsbin with js console open you'll see there is one template 'application' in the array. My guess is that the array will be empty if you try the same in your environment.
There are many ways to get that done, which is right depends on your environment. Since you're running on port 3000 I'm gonna guess that's rails. In that case check out the ember-rails gem. By far the simplest short-term approach is to define templates using script tags within the HTML page, as I've done in the jsbin.
Related
I'm new to EmberJs and I'm working on a project that I need to add properties in javascript and css in templantes generated by ember-cli, my difficulty is in finding the javascript and css files
When I search the project for the class or id, it shows me only what is in the dist that can not be changed
Can anyone with emberJS experience help me make these changes?
Template with i w[enter image description here][1]anna to work:
<div class="top-banner">
{{ top-banner pageBanner=model.news.banner }}
{{ search-component exchangeTypes=model.exchangeType}}
</div>
{{bread-crumbs breadcrumbs=breadcrumbs}}
<section class="container destaque noticia">
{{title-content light=model.news.title}}
<div class="row informacoes-news">
<div class="col-xs-12 noticia-texto">
{{{model.news.content}}}
</div>
</div>
</section>
{{share-bar}}
<div class="col-md-1 col-xs-12 download-container">
<a class="teste" href="{{model.news.pdf}}">Download</a>
</div>
{{featured-news type="featured_news" noticias=model.featuredNews news=true}}
{{contact-widget states=model.brazilState}}
{{rodape-sitemap}}
Here is an outline of the basics in an ember-twiddle: https://ember-twiddle.com/f537e51449c1c49ae32794b9d15bc6ff?openFiles=templates.application.hbs%2C
It sounds like you inherited some code - and like you'd benefit from spending a few hours with the Ember guides tutorial: https://guides.emberjs.com/current
Happy travels!
application.hbs
<h1>{{appName}}</h1>
<h2>this is the application.hbs template (base template)</h2>
{{info-list}}
controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'this is a property value seen in the application template...',
});
app.css
body {
background: lightgreen;
}
templates/components/info-list.hbs
<ul class='item-list'>
<li>...</li>
</ul>
I'm new to Ember, I want to add some query DOM manipulation code to the element in the {{#each}} block. So I google it up and found the solution from this guide:
views/products/index.js
import Spinner from 'appkit/utils/someJqueryCode';
Ember.View.reopen({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent : function(){
// implement this hook in your own subclasses and run your jQuery logic there
}
});
export default Ember.View.extend({
afterRenderEvent: function() {
Spinner();
}
});
templates/products/index.hbs
<div class='panel panel-default products'>
<div class='panel-heading'>
<h2 class='panel-title'>Our Prodcuts</h2>
</div>
<div class='panel-body'>
<ul class='row'>
{{#each}}
<li class='col-md-4'>
<div class='thumbnail'>
<img {{bind-attr src=url alt=alt}} />
</div>
<div class='caption'>
<h3 class='name-me'>{{name}}</h3>
<p>{{description}}</p>
<div class='row no-gutter'>
<div class='col-xs-3'>
<button class='btn btn-primary'>Buy</button>
</div>
</div>
</div>
</li>
{{/each}}
</li>
</div>
</div>
But I seems after the point when afterRenderEvent() is triggered, all the elements in the {{#each}} block hasn't been rendered to the DOM yet, thus, the jQuery code return undefined
What's the right way to do it?
Your view's didInsertElement hook will fire as soon as the application route is rendered, which happens before the index route. You might think that putting it in the index.js file will work, but it's going to just extend the default application view behavior.
You need to create a more focused view that lives within your index.hbs file. One that is only concerned with your spinner jQuery doohickey. That, and an each/else conditional could work nicely here. For example:
{{#each}}
{{#view App.SpinnerDoohickeyView}}
<li class='col-md-4'>
<div class='thumbnail'>
<img {{bind-attr src=url alt=alt}} />
</div>
<div class='caption'>
<h3 class='name-me'>{{name}}</h3>
<p>{{description}}</p>
<div class='row no-gutter'>
<div class='col-xs-3'>
<button class='btn btn-primary'>Buy</button>
</div>
</div>
</div>
</li>
{{/view}}
{{else}}
<li>Empty collection!</li>
{{/each}}
Notice that I've wrapped each list item in its own view. You could wrap the whole ul if you wanted... this is just an example. The idea is that you are only creating views when you have a model.
And now you can define the view, and simply use the didInsertElement hook to work with jQuery:
App.SpinnerDoohickeyView = Ember.View.extend({
didInsertElement: function () {
this.$('li').css('background', 'blue');
}
});
If you have a model to render, jQuery should be able to safely access it this way. Good luck!
Here's some further reading and some code from the Ember folks that looks like what I've shown you here: http://emberjs.com/guides/views/handling-events/
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.
This is pretty basic, but I've spent hours trying to figure out why I can't seem to use Handlebars's built-in #if helper inside the #each loop of my template. The second I insert a reference to {{#if}}, Chrome (or Safari) crash and the console reports:
Uncaught RangeError: Maximum call stack size exceeded
meta
targetSetFor
sendEvent
Ember.Evented.Ember.Mixin.create.trigger
Ember.CoreView.Ember.Object.extend.trigger
newFunc
(anonymous function)
Ember.View.Ember.CoreView.extend.invokeRecursively
newFunc
(repeats many times)
Why is this causing me a recursion fault in Ember?
<div id="gridChannelListDiv" tabindex="0">
{{#each item in content}}
{{#if item.hilight}}
<div class="gridCellHilight">
...
</div>
{{else}}
<div class="gridCell">
...
</div>
{{/if}}
{{/each}}
</div>
This happens even if the {{#if}} statement does nothing.
<div id="gridChannelListDiv" tabindex="0">
{{#each item in content}}
{{#if}}{{/if}} // this line will cause instant "oh snap" crash
<div class="gridCell">
{{item.name}}
</div>
{{/each}}
</div>
The associated ArrayController contains a simple list of 5 Ember objects in "content" and the templates work fine until I insert an #if.
Baffled.
There does not seem to be anything wrong with your code. Could be a bug in your version of ember or perhaps an incompatible version of a supporting library (handlebars/jQuery). Either that or something crazy going on in some other aspect of your application.
I created a simple app/controller and used it to get your template code up and running here: http://jsbin.com/ekemak/2/edit - Tried in both chrome and safari, in both cases app works with no js errors.
//app.js
App = Ember.Application.create({});
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', [
Em.Object.create({name: 'aaa', hilight: false}),
Em.Object.create({name: 'BBB', hilight: true}),
Em.Object.create({name: 'ccc', hilight: false})
]);
}
});
//index.hbs
<ul>
{{#each item in content}}
{{#if item.hilight}}
<div class="gridCellHilight">
<B>{{item.name}}</B>
</div>
{{else}}
<div class="gridCell">
{{item.name}}
</div>
{{/if}}
{{/each}}
</ul>
I have the following code in a ember.js template. userController is an ArrayController, with multipe "users" within.
{{#each CollaborativeEditor.userController}}
{{#view CollaborativeEditor.OnlineUserView userBinding="this"}}
<div class="avatar">
<div class="avatar_name">{{name}}</div>
<div class="avatar_status">{{status}}</div>
</div>
<div id="dropdown-1">
<ul>
<li><a href="#" {{action startChat target="onlineUser"}}>Talk to </a></li>
</ul>
</div>
{{/view}}
{{/each}}
This is the code of the respective view:
CollaborativeEditor.OnlineUserView = Ember.View.extend({
tagName: 'li',
startChat : function() {
console.log(this.get('user'));
}
});
Although, the name and status is set correctly for each user, the startChat action attached to the link always prints the first user of the array to the console.
What is wrong with the binding ?
Thanks a lot for your request, to put it in a jsfiddle !
While I was trying to reproduce the error there, I realized the problem, and it has nothing to do with ember.
The div with id="dropdown-1" was called from another link and it was always the same id, therefore always the same action with its user-binding.
Now I've bound the Id to the user-object and it works perfectly.