I tried this very basic ember router example following the ember-router-example. But when I run it, it shows me an empty page. I checked the console window for any errors, but seems to be fine. Not really sure why this is not working and where am missing.
I am just trying to create the first level links of Home, Sections, items only.
Can somebody help me?
index.html:
<body>
<script src="js/libs/jquery-1.7.1.js"></script>
<script src="js/libs/jquery.lorem.js"></script>
<script src="js/libs/bootstrap.min.js"></script>
<script src="js/libs/handlebars-1.0.0.beta.6.js"></script>
<script src="js/libs/ember.js"></script>
<script src="js/app.js"></script>
<script type="text/x-handlebars" data-template-name="application">
<div>
<ul>
<li><a {{action "doHome"}}>Home</a></li>
<li><a {{action "doSections"}}>Sections</a></li>
<li><a {{action "doItems"}}>Items</a></li>
</ul>
</div>
<div>
{{outlets}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="home">
<h1>yeah right Home</h1>
</script>
<script type="text/x-handlebars" data-template-name="sections">
<h1>Oh v in Sections index</h1>
</script>
<script type="text/x-handlebars" data-template-name="items">
<h1>correct in Items Index Page</h1>
</script>
</body>
app.js :
$(function() {
App = Ember.Application.create()
App.ApplicationController = Ember.Controller.extend();
App.ApplicationView = Ember.View.extend({
templateName:'application'
});
App.HomeController = Ember.Controller.extend();
App.HomeView = Ember.View.extend({
templateName:'home'
});
App.SectionsController = Ember.Controller.extend();
App.SectionsView = Ember.View.extend({
templateName:'sections'
});
App.ItemsController = Ember.Controller.extend();
App.ItemsView = Ember.View.extend({
templateName:'items'
});
App.Route = Ember.Route.extend({
root: Ember.Route.extend({
doHome : function(router,event){
router.transitionTo('home');
},
doSections:function(router,event){
router.transitionTo('sections');
},
doitems:function(router,event){
router.transitionTo('items');
},
home : Ember.Route.extend({
route : '/',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('home');
}
}),
sections : Ember.Route.extend({
route : '/sections',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('sections');
}
}),
items : Ember.Route.extend({
route : '/items',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('items');
}
})
})//root
}) //router
});
I created this fiddle with your code. It seems to be working, just use latest ember and handlebars. And maybe you should change {{outlets}} with {{outlet}}.
EDIT
The above fiddle is not working, see the updated fiddle.
I rewrote the routing code using the new routing API, now it is working as expected.
I believe you are supposed to be using "template" as opposed to templateName when you are defining your templates in your main html file. If you were to create those templates as separate handlebars files and use a build step, you would then use templateName to refer to them (by file name).
Steve
Related
I have a route in an Ember app called "basic" corresponding to the name of an API endpoint.
This route doesn't work - links to it don't render its template.
Here's a JSBin demonstrating the failure: http://emberjs.jsbin.com/hisoxadi/1
JS:
App = Ember.Application.create();
App.Router.map(function() {
this.route('basic');
this.route('test');
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
Templates:
<script type="text/x-handlebars">
<h2> Welcome to Ember.js</h2>
{{#link-to 'index'}}Index{{/link-to}}
{{#link-to 'basic'}}Basic Route{{/link-to}}
{{#link-to 'test'}}Test Route{{/link-to}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="basic">
basic route is here
</script>
<script type="text/x-handlebars" data-template-name="test">
test route is here
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
To expand on your comment a bit, basic is indeed a reserved word. Specifically, it's a reserved word for the resolver. You can see the source here.
useRouterNaming: function(parsedName) {
parsedName.name = parsedName.name.replace(/\./g, '_');
if (parsedName.name === 'basic') {
parsedName.name = '';
}
},
And because of the way that Ember.js sometimes looks up routes and controllers in the container, it's a fair bet to say that there's no way around this without major code changes. There should probably be a documentation issue filed for this.
EDIT: I created an issue for this here.
I am trying to use different Adapters for 2 different Ember Models but this setup seems to be having problems. I'm able to fetch(find) the 2 models using their respective adapters but when i try to save(commit) them, an issue arises and both try to use the first model's adapter only.
<html>
<head>
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="js/handlebars.js"></script>
<script type="text/javascript" src="js/ember-latest.js"></script>
<script type="text/javascript" src="js/ember-data-latest.js"></script>
</head>
<body>
<script type="text/x-handlebars" id="application">
<h1>Application</h1>
{{ outlet }}
</script>
<script type="text/x-handlebars" id="index">
<h1>Index</h1>
<b>Create</b>
<a href="#" {{action "createOne"}}>Create One</a>
<a href="#" {{action "createTwo"}}>Create Two</a>
<hr>
<b>Load</b>
<a href="#" {{action "loadOne"}}>Load One</a>
<a href="#" {{action "loadTwo"}}>Load Two</a>
</script>
<script>
App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.extend({
url: "/one"
})
});
App.Store.registerAdapter("App.Two",DS.RESTAdapter.extend({
url: "/two"
}));
App.One = DS.Model.extend({
name: DS.attr("string",{defaultValue:"one"})
});
App.Two = DS.Model.extend({
name: DS.attr("string",{defaultValue:"two"})
});
App.IndexController = Ember.ObjectController.extend({
createOne: function() {
App.One.createRecord({}).save();
},
createTwo: function() {
App.Two.createRecord({}).save();
},
loadOne: function() {
App.One.find();
},
loadTwo: function() {
App.Two.find();
}
});
</script>
</body>
</html>
The Load One and Load Two links work well and hit the url's GET one/ones and GET two/twos respectively. But On using Create One and Create Two links the links hit are PUT one/ones and PUT one/twos. and not one/ones and two/twos. So Ember is trying to hit the second click of creating two with One's adapter and not changing it to Two's Adapter.
Any idea anyone ?
I'm building a front-end (on top of Ruby on Rails) using ember.js and the ember-rails gem.
My (ember) application consists of Models, Views, Controllers and an application.handlebars template which describes my UI.
Whats the best practice to break up this application.handlebars file so that I can manage the UI? For example, I'd like to have Navigation at the top of the page.
I've tried using the Ember.Router, a separate navigation.handlebars (with NavigationView and NavigationController) the {{outlet}} helper to no avail. Here's what the Router looks like:
App.Router = Ember.Router.extend(
enableLogging: true
root: Ember.Route.extend(
index:
route: '/'
connectOutlets: (router, context) =>
router.get('applicationController').connectOutlet('navigation')
)
and the application.handlebars
<h1>Lots of HTML that I want to break up</h1>
{{outlet}}
Let me know if you need more info...thanks.
As per my Understanding, Let's suppose you want 3 sections(can be any number) Header, Content & Footer, You can do something as follows
<script type="text/x-handlebars" data-template-name="application">
{{view MyApp.HeaderView}}
{{#view MyApp.ContentView}}
{{outlet}}
{{/view}}
{{view MyApp.FooterView}}
</script>
<script type="text/x-handlebars" data-template-name="app-header">
All your Header related HTML
</script>
<script type="text/x-handlebars" data-template-name="app-content">
HTML related to content
{{yield}} //this will be explained at the end
More HTML if you want
</script>
<script type="text/x-handlebars" data-template-name="app-footer">
HTML related to footer
</script>
MyApp.HeaderView = Ember.View.extend({
templateName: 'app-header'
})
MyApp.ContentView = Ember.View.extend({
templateName: 'app-content'
})
MyApp.FooterView = Ember.View.extend({
templateName: 'app-footer'
})
MyApp.ApplicationView = Ember.View.extend({
templateName: 'application'
})
explaining {{yield}} In a nutshell, whatever is between in the block helper of a given view goes in there, In the above example for the MyApp.ContentView, the {{outlet}} defined in the {{#view MyApp.ContentView}} handlebars gets inserted at the {{yield}}
On the similar lines let me show the difference between layoutName property & templateName property,
App.someView = Ember.View.extend({
tagName: 'a',
templateName: 'a-template',
layoutName: 'a-container'
})
<script type="text/x-handlebars" data-template-name="a-template">
Hi There
</script>
<script type="text/x-handlebars" data-template-name="a-container">
<span class="container">
{{yield}}
</span>
</script>
Will result in following HTML
<a class="ember-view" id="ember235">
<span class="container ember-view" id="ember234">
Hi There
</span>
</a>
Use these concepts to split the application handlebars in your case it would be something like
{{view App.NavigationView}}
{{outlet}}
Update as per latest ember
The new ember supports partials similar to rails, now we can modify the above to use {{partial}} as follows:
{{partial "header"}}
{{outlet}}
{{partial "footer"}}
Ember when encountered this template will look for the template whose name is _header(similar to rails) and inserts the template(same goes for footer)
And If want to associate a controller we can use {{render}} helper
{{render "sidebar"}}
inserts the template whose name is sidebar at specified location in handlebars besides it also associates App.SidebarController to it,
Note: we cannot use {{render 'sidebar'}} more than once in same handlebars file.
But again if you want to use a widget like view multiple places in a given page then use {{view}} helper
For this problem, what you need to do is think about what views change and where that changes happen. If for example you have a navigation section and a main section, then think about how each of these sections change with the state of your application. Be sure to only create an {{outlet}} for dynamic content, otherwise things will get messy and the application will be slower. Then setup your templates and your router similar to the example below.
Templates:
<script type="text/x-handlebars" data-template-name="application">
<!--Your application template goes here-->
{{outlet navigation}}
{{outlet body}}
</script>
<script type="text/x-handlebars" data-template-name="navigation">
<!--Your navigation template goes here-->
</script>
<script type="text/x-handlebars" data-template-name="main-one">
<!--Your mainOne template goes here-->
</script>
<script type="text/x-handlebars" data-template-name="main-two">
<!--Your mainTwo template goes here-->
</script>
Note: You can have {{outlet}} in any of your view templates to change in more sub-states
Javascript:
window.App = Em.Application.create({
ApplicationView: Em.View.extend({
templateName: "application"
}),
ApplicationController: Em.Controller.extend({
}),
NavView: Em.View.extend({
templateName: "navigation"
}),
NavController: Em.Controller.extend({
}),
MainOneView: Em.View.extend({
templateName: "main-one"
}),
MainOneController: Em.Controller.extend({
}),
MainTwoView: Em.View.extend({
templateName: "main-two"
}),
MainTwoController: Em.Controller.extend({
})
Router: Em.Router.extend({
root: Em.Route.extend({
index: Em.Route.extend({
route: '/',
connectOutlets: function(router,context) {
router.get("applicationController").connectOutlet("navigation","nav");
router.get("applicationController").connectOutlet("body","mainOne");
}
}),
otherState: Em.Route.extend({
route: '/other-state',
connectOutlets: function(router,context) {
router.get("applicationController").connectOutlet("navigation","nav");
router.get("applicationController").connectOutlet("body","mainTwo");
}
}),
})
})
});
App.initialize();
Note: The applicationController must extend Controller and not ObjectController or ArrayController
I am researching Ember and i wanna know if it is possible to include multiple views in a single page and switch between layout templates. I've developed with AngularJS before.
I am searching for an Ember equivalent of this $route.when('/view1', ...); and <ng-include src="templates.top" />.
Here is a working fiddle for Angular. I hope someone can help me because i found little help.
In it's simplest form, you can use StateManager. Please see the following fiddle I created: http://jsfiddle.net/npCfF/
Javascript:
App= Ember.Application.create();
App.StateManager = Ember.StateManager.create({
rootElement: '.tab-content',
initialState: 'tab1',
//Show the location tab function
showTab1: function(manager) {
manager.transitionTo('tab1');
},
//show seleceted areas
showTab2: function(manager) {
manager.transitionTo('tab2');
},
showTab3: function(manager) {
this.set('locationActive', 'inactive');
this.set('areasActive', 'active');
this.set('filterActive', 'inactive');
this.set('childOf', 'showAreas');
manager.transitionTo('tab3');
},
tab1: Ember.ViewState.create({
route: 'tab1',
view: Ember.View.create({ templateName: 'tab1' })
}),
tab2: Ember.ViewState.create({
route: 'tab2',
view: Ember.View.create({ templateName: 'tab2' })
}),
tab3: Ember.ViewState.create({
route: 'tab3',
view: Ember.View.create({ templateName: 'tab3' })
})
});
HTML:
<script type="text/x-handlebars">
<nav class="tab_menu">
<span id="tab_location_result" data-show="location_result" {{action "showTab1" target="App.StateManager"}}><i class="icon-globe"></i>Tab 1</span> |
<span id="tab_selected_areas" data-show="selected_areas" {{bindAttr class="MapSearch.StateManager.areasActive"}} {{action "showTab2" target="App.StateManager"}}><i class="icon-map-marker"></i>Tab 2</span> |
<span id="tab_filter_results" data-show="filter_results" {{bindAttr class="MapSearch.StateManager.filterActive"}} {{action "showTab3" target="App.StateManager"}}><i class="icon-filter"></i>Tab 3</span>
</nav>
</script>
<div class="tab-content"></div>
<script type="text/x-handlebars" data-template-name="tab1">
Tab1
</script>
<script type="text/x-handlebars" data-template-name="tab2">
Tab2
</script>
<script type="text/x-handlebars" data-template-name="tab3">
Tab3
</script>
What you're thinking of is the Ember.js router, with Handlebars.js templates on top. Here is a good guide to it, it covers everything you'll need to get started. Reading through and understanding the tutorial might take some time.
i have 3 tabs navigation and the content of each tab is different obviously.
i'm thinking about using StateManager in Emberjs to manager my tab views.
http://docs.emberjs.com/#doc=Ember.StateManager&src=false
is that a good idea? or is there a better router out there? i've looked at
sproutcore-routing
ember-routemanager
are those better than the statemanager? what's the reason not to use statemanager?
You can use something along this lines, see http://jsfiddle.net/pangratz666/e3wM7/:
Handlebars:
<script type="text/x-handlebars" >
<ul>
<li {{action "showFirst" target="App.stateManager"}} >First tab</li>
<li {{action "showSecond" target="App.stateManager"}} >Second tab</li>
</ul>
<div class="tab-content" ></div>
</script>
<script type="text/x-handlebars" data-template-name="first" >
first
</script>
<script type="text/x-handlebars" data-template-name="second" >
second
</script>
JavaScript:
App.stateManager = Ember.StateManager.create({
rootElement: '.tab-content',
initialState: 'firstTab',
showFirst: function(manager) {
manager.goToState('firstTab');
},
showSecond: function(manager) {
manager.goToState('secondTab');
},
firstTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'first' })
}),
secondTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'second' })
})
});
Also take a look at the blog post Anatomy of an Ember.js App Part I Redux: Routing and Outlets.