Creating a Lightbox Route in Ember.js - ember.js

My authentication system uses lightboxes, so that when a user clicks "Sign In" or "Sign Up", a lightbox pops up for them to input their credentials. The page they were on remains rendered behind the lightbox, and when they're done signing in, the lightbox disappears and the view returns to the way it was. I can get this to work when I deviate from the conventional Ember route flow by using a lot of Jquery, but I'd prefer to integrate this more tightly into the rest of my Ember app.
The problem is, the conventional Ember route flow expects views and templates to be handled in a particular way. Specifically, a route such as /sign-in will render the sign-in template within the application template, erasing whatever was there before. Since I want to preserve the view that was there before, this approach doesn't work.
Is there a way to tell an Ember view not to erase the current view, but instead to render an independent view such as a lightbox?

You can use named outlets and render a template into the outlet, in my aplication template I has an outlet called modal, and two actions in the ApplicationRoute, openModal and closeModal. The open one receives a template name and uses the route method render to set the outlet content, the close one renders an empty template.
App.ApplicationRoute = Ember.Route.extend({
actions: {
openModal: function(modal) {
this.render(modal, {into:'application', outlet: 'modal'});
},
closeModal: function() {
this.render('empty', {into: 'application', outlet: 'modal'});
},
}
});
Html handelbars
<script type="text/x-handlebars" data-template-name="application">
{{! Other application template code}}
<button {{action openModal 'hellow.modal'}}>Open it!</button>
{{outlet modal}}
</script>
<script type="text/x-handlebars" data-template-name="empty"></script>
<script type="text/x-handlebars" data-template-name="hellow/modal">
<div class="modal">
<div class="modal-header">
Hellow
</div>
<div class="modal-footer">
<button {{action closeModal}}>Close</button>
</div>
</div>
</script>
This is adapted from http://nerdyworm.com/blog/2013/04/20/ember-modal-example/

Related

Ember.js {{linkTo}} to itself does not render

I have a problem with a linkTo that points to itself. The actual problem is in an application that has a sidebar with a set of links. The first time a click the link the model and view is loaded and displayed properly. However on the second click the view and/or model disappear.
I've condensed the problem in this jsfiddle. The index route displays a list of links and when clicking on one of the links it will display the detail. In the detail page I have a link to itself but when I click it the model does not show.
The detail template shows the content fine but note the {{firstName}} or {{lastName}}
<script type="text/x-handlebars" data-template-name="item">
<h2>Item Content:</h2>
{{#linkTo "item" id}}Reload me{{/linkTo}}
{{content}}
<ul>
<li>{{firstName}} {{lastName}}</li>
</ul>
</script>
I think the issue is similar to Ember.js - linkTo error on second call
Updated sample
Here is a new example With linkTo at the top levelwhere the {{linkTo}} item is in the top level application template
<script type="text/x-handlebars" data-template-name="application">
{{#linkTo "test" 0}}Test 0{{/linkTo}}
{{outlet}}
</script>
Following #intuitivepixel solution using an action gives me the same result
<script type="text/x-handlebars" data-template-name="application">
<a href="#" {{action reloadMe "test" 0}}>Test 0</a>
{{outlet}}
</script>
Not everything can be done with the {{linkTo}} helper, IMO for this kind of feature (like a reload) you should go for a {{action}} helper instead.
First define the action that does the routing for you when called:
App.TestRoute = Ember.Route.extend({
events: {
reloadMe: function(route, content) {
this.transitionTo(route, content);
}
},
serialize: function(model) {
return {id: model.id};
}
});
And then in your template:
<a href="#" {{action reloadMe "test" content}}>Reload me</a>
See here how you could implement it: http://jsfiddle.net/FSd6H/4/
Hope it helps.

Ember.js: Toggle Nested Views

I have a header with some login/signup forms that popup when you click the respective buttons.
While it was working fine using just jQuery, I've now started to integrate Ember into the application and I'm running into some trouble with some simple toggle functionality.
Here's the basic HTML markup:
<header>
<h1>Page Title<h1>
<nav>
<a id="toggles-login" class="button {{active_class_binding}}">Login</a>
<a id="toggles-signup" class="button {{active_class_binding}}">Signup</a>
</nav>
<div id="popup-forms">
<div id="login-form"></div>
<div id="signup-form"></div>
</div>
<header>
I'm completely new to Ember and I really have no idea how to set this up. The only thing I want is to be able to set the popup forms up as Ember.View objects and toggle them with some action helpers.
I really am lost on this one.
A simple solution would be to trigger simple actions to show the respective forms:
<a id="toggles-login" class="button {{active_class_binding}}" {{action showLoginForm target="view"}}>Login</a>
<a id="toggles-signup" class="button {{active_class_binding}}" {{action showSignupForm target="view"}}>Signup</a>
The corresponding view would have to implement both actions:
App.YourView = Ember.View.extend({
showLoginForm : function(){
this.$("#login-form").toggle();
},
showSignupForm : function(){
this.$("#signup-form").toggle();
}
});

Adding a new object to an ArrayController

I am attempting to create a basic CRUD setup for managing 'User' objects in Ember. I think I have my models and routes in order. I'm struggling with managing:
A) The proper controller setup for the (all) users page. I think that I should be creating an ArrayController, but it seems to work fine automatically. Does my Ember App know to make an array of individual 'user' objects? if so, how?
B) Passing data from InputFields. If you click 'Add User' in my example, I have made a form to create a user. When you click 'create', I'm not sure how to get the textField values, nor do I understand what to do with those values once I have them. How would I update my controller?
Again, here a jsbin of my code. Any guidance would be greatly appreciated.
Regarding A):
I assume you refer to the following route of your App. This model function returns an Array. Therefore Ember knows that it should use an ArrayController to render your UsersRoute.
App.UsersIndexRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
Regarding B): I have updated your code -> http://jsbin.com/ozilam/15/edit
I needed to update some of your names (controller and view) to match the naming conventions of Ember.
With Ember you do not have to use forms and manually read those values. Instead you create a new records, when you enter your Route:
App.UsersNewRoute = Ember.Route.extend({
setupController : function(controller){
controller.set("content", App.User.createRecord({}));
}
});
Inside your View you are binding on the properties of your record. As you see i also updated your button with an action helper.
<script type="text/x-handlebars" data-template-name="users/new">
<div class="row">
<div class="six columns">
<h3>New User Information</h3>
<form>
<label>First Name</label>
{{view Ember.TextField valueBinding='name_first'}}<br />
<label>Last Name</label>
{{view Ember.TextField valueBinding='name_last'}}<br />
<label>Email Address</label>
{{view Ember.TextField valueBinding='email_address'}}<br />
<label>SSN</label>
{{view Ember.TextField valueBinding='ssn'}}<br />
<button {{action create target="view"}} class="button">Create</button>
{{#linkTo users}}Cancel{{/linkTo}}
</form>
</div>
</div>
</script>
As those changes in the form get automatically propagated to your controller, you can just access the object in the controller:
App.UsersNewView = Ember.View.extend({
didInsertElement: function() {
this.$('input:first').focus();
},
create: function(){
console.log('view submitted');
var newUser = this.get("controller.content");
console.log(newUser.get("name_first"));
console.log(newUser.get("name_last"));
// HOW DO I PROCESS THIS FORM
}
});
Note: As i am writing this i am realizing that it would be probably better, if you would handle this event in your Controller instead of the View, since its an data modification task.

When to render via render and when via view?

I'm trying to figure out when to render a custom view with render and when via view. I know that rendering with render we get the full context (view, controller). But what about view? View is supposed to be for custom views and handing events.
The example below comes form ember data example
contacts.hbs
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">All contacts</li>
{{#each contact in controller}}
{{view App.ContactInListView contentBinding="contact"}}
{{/each}}
</ul>
</div>
</div>
<div class="span9">
{{outlet}}
</div>
contact_in_list_view.hbs
App.ContactInListView = Em.View.extend({
templateName: 'contact_in_list',
tagName: 'li',
classNameBindings: 'isActive:active',
isActive: function() {
return this.get('content.id') === this.get('controller.activeContactId');
}.property('controller.activeContactId')
});
contact_in_list.hbs
{{#linkTo "contact" contact}}{{contact.fullName}}{{/linkTo}}
Couldn't just I render contact_in_list with render and pass it some controller?
When should I use render and when view? What's the rule of thumb?
Couldn't just I render contact_in_list with render and pass it some controller?
The {{render}} helper can be passed a model but not controller. Probably what you want in this case is the {{each}} helper's itemController property
{{#each contact in controller itemController="contactInList"}}
{{view App.ContactInListView}}
{{/each}}
Have a look at API docs for Ember Handlebars.helpers
When should I use render and when view? What's the rule of thumb?
Use the {{render}} helper when you want to render a view/template in the current context using the singleton instance of the same-named controller.
Use the {{view}} helper when you want to render a view in the current context without changing to another controller. Like {{view Ember.TextField}}

Change Navbar based on login state

I’ve been trying, using Rails/Ember pre-4, to do a fairly typical thing, that is have a page with a navbar and a content section. The navbar only changes on login (shows logout button when logged in and login and register buttons when logged out), not on every page change.
At first thought i could do something in the application.hbs template such as:
{{view navbar}}
{{outlet}}
where i set up navbar to respond to login state changes (managed by a state manager). This didn’t seem to work.
Then i tried something like (also in application.hbs):
{{outlet navbar}}
{{outlet}}
and tried setting navbar in each route, which results in lots of duplication and also didn’t ultimately work.
Before posting code, wanted to know if anyone already has a good solution to this common situation where certain parts of your page such as a navbar or sidebar only change upon some change in app state, not on every page change.
There are lots of ways to get this done. The first approach you described is closest to what we are doing. In past ember versions we used view helper for this, today we use {{render}} but it's the same basic concept. For example, application.hbs might look like this:
{{render navbar}} {{outlet}}
Now navbar.hbs can use a simple {{#if}} helper to swap links based on login state.
<div class="navbar">
<div class="navbar-inner">
{{#linkTo index class="brand"}}My App{{/linkTo}}
<ul class="nav">
<li>{{#linkTo index}}Home{{/linkTo}}</li>
<li>{{#linkTo about}}About{{/linkTo}}</a></li>
</ul>
<ul class="nav pull-right">
{{#if isAuthenticated}}
<li><a {{action logout}} href="#">Logout</a></li>
{{else}}
<li><a {{action login}} href="#">Login</a></li>
{{/if}}
</ul>
</div>
</div>
Now we add logic to NavbarController that tracks and manages login state.
App.NavbarController = Ember.ArrayController.extend({
isAuthenticated: false,
login: function() {
this.set('isAuthenticated', true);
},
logout: function() {
this.set('isAuthenticated', false);
}
});
In a real app NavbarController would proxy these requests to another controller, perhaps currentUserController. I've created a working sample here: http://jsbin.com/iyijaf/6/edit