Ember: How do bindings work in the application template? - ember.js

I have a boolean variable focusBool that hide the menu of the Web App when True. The Application template with the {{#if}} statement is below:
<script type="text/x-handlebars">
{{#if focusBool}}
<nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
{{#link-to 'home' tagName="li"}}
{{#link-to 'home'}}
Home
{{/link-to}}
{{/link-to}}
{{#link-to 'books' tagName="li"}}
{{#link-to 'books'}}
Books
{{/link-to}}
{{/link-to}}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav
{{/if}}
<div class='container-fluid'>
{{outlet}}
</div>
</script>
This variable has been injected to all routes, controllers and components. When the focusBool is changed to true after the Application has loaded, the menu items do not disappear. How can I have the Application template be rerendered when the focusBool is modified? My understanding is that the {{#if focusBool}} would monitor when focusBool value change and show or hide the menu accordingly?
Here more related code:
App.Session = Ember.Object.extend({
user: null,
focusBool: false,
userID: '',
});
Injection:
Ember.Application.initializer({
name: 'login',
initialize: function (container, application) {
App.register('session:main', App.Session.create(), { instantiate: false, singleton: true });
// Add `session` object to route to check user
App.inject('route', 'session', 'session:main');
// Add `session` object to controller to visualize in templates
App.inject('controller', 'session', 'session:main');
// Add `session` object to session to visualize in templates
App.inject('component', 'session', 'session:main');
}
});
The Application Route:
App.ApplicationRoute = Ember.Route.extend({
isAutheticated: null,
actions: {
login: function() {
//var session = this.get('session.');
var isAuth = false;
var store = this.store;
var user = null;
var _this = this;
var firebase = new Firebase("https://dynamicslife.firebaseio.com");
firebase.authWithOAuthPopup('facebook', function(error, authData) {
if (error) {
isAutheticated = false;
console.log('failled login attempt', error);
} else if (authData) {
isAutheticated = true;
console.log('user authenticated with Firebase', authData.uid);
var record = store.find('user', authData.uid).then(function(_user) {
console.log('user exist in Firebase');
_this.session.set('userID', authData.uid);
//_this.rerender();
}, function(error) {
// user does not exist or some other error
store.unloadAll('user');
user = store.createRecord('user', {
id: authData.uid,
uid: authData.uid,
displayName: authData.facebook.displayName,
});
user.save();
_this.session.set('userID', authData.uid)
_this.rerender();
console.log('New user created in Firebase');
});
}
});
},
logout: function() {
var firebase = new Firebase("https://dynamicslife.firebaseio.com");
firebase.unauth();
isAuth = false;
this.session.set('userID', '');
console.log('logged out');
}
}
});

At first glance it seems your referencing focusBool incorrectly in the template. Since you're injecting the session object, you should reference it like session.focusBool in the template.
Here is a working demo.

Related

Computed Property not working

I'm writing the todo app and I can't get computed properties working. I want to implement computed properties in the todos/index controller so that the template can appropiately display the amount of todos undone remaining (based on the isCompleted attribute of the models).
This is the code:
todos/index.hbs
{{input type="text" id="new-todo" placeholder="What needs to be done?" value=newValue action="createTodo"}}
<section id="main">
<ul id="todo-list">
{{#each model as |todo|}}
{{todo-item todo=todo edit="editTodo" destroy="destroyTodo"}}
{{/each}}
</ul>
<input type="checkbox" id="toggle-all">
</section>
<footer id="footer">
<span id="todo-count">
<strong> {{remaining}} </strong> todos left
</span>
<ul id="filters">
<li>
All
</li>
<li>
Active
</li>
<li>
Completed
</li>
</ul>
<button id="clear-completed">
Clear completed {{completed}}
</button>
</footer>
todos/index.hbs
import Ember from 'ember';
export default Ember.ArrayController.extend({
remaining: function() {
var todos = this.get('model');
return todos.filterBy('isCompleted', false).get('length');
}.property('todos.#each.isCompleted'),
completed: function() {
var todos = this.get('model');
return todos.filterBy('isCompleted', true).get('length');
}.property('todos.#each.isCompleted'),
actions: {
createTodo: function() {
this.get('newValue');
var newTodo = this.store.createRecord('todo', {title: this.get('newValue'), isCompleted: false});
this.set('newValue', '');
},
editTodo: function(todo) {
if (Ember.isEmpty(todo.get('title'))) {
this.send('destroyTodo', todo);
}
else {
todo.save();
}
},
destroyTodo: function(todo) {
debugger;
todo.deleteRecord();
}
}
});
In case it helps: https://github.com/FranGoitia/todo
Thanks.
You should be watching for changes on model.#each.isCompleted, todos is not a property of your controller (it's just a local variable inside your computed property).

ember js 'undefined' in url

This is my menu bar code in html
<script type="text/x-handlebars" data-template-name="links">
<div class="navbar navbar-inverse navbar-fixed-top">
<ul class="nav nav-pills">
<li>{{#link-to "myleaves" 1255 action="myleavesinfolist"}}My Leave{{/link-to}}</li>
<li>{{#link-to "approvalrequests" 1255 action="appreqlist"}}Approval Requests{{/link-to}}</li>
<p class="navbar-text navbar-right"><button type="button" class="btn btn-info" {{action "logout"}}>Logout</button></p>
<p class="navbar-text navbar-right"><font color="white" size=4>Welcome {{model.userName}}</font></p>
</ul>
</div>
{{outlet}}
Here is my ember js code
App.Router.map(function () {
this.resource("signin", {path: "/"});
this.resource("links", {path: "/:id"},
function () {this.resource("myleaves",path: "/myleaves/:id"});
this.resource("approvalrequests", {path: "/appreq/:id"});
});
});
am bringing data by below code
App.LinksController = Ember.ObjectController.extend({
actions: {
myleavesinfolist: function () {
rdata = $.ajax({
type: "POST",
url: "/myleaves",
dataType: "json",
async: false
}).responseJSON;
this.transitionToRoute("myleaves", rdata);
} //myleavesinfolist
,
appreqlist: function () {
rdata = $.ajax({
type: "POST",
url: "/aprreq",
dataType: "json",
async: false
}).responseJSON;
final = filterData(rdata);
console.log(final);
this.transitionToRoute("approvalrequests", final);
} //appreqlist
} //actions
}); //controller
but when i click on menu link "myleaves " or "approval requests"
my url is like
http://localhost:8888/Leave.html#/undefined/myleaves/undefined
i dont knw why this undefined is coming..
PLease help
am a newbie
link-to expects a model object as its second argument, rather than an id.
So you’ll likely want to load the models for myleaves and approvalrequests earlier on—perhaps in your ApplicationRoute:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
myLeaves: this.store.find('leaves'), // or however you fetch model data
approvalRequests: this.store.find('approval-request') // ditto
});
}
});
And the template becomes:
<script type="text/x-handlebars" data-template-name="links">
<div class="navbar navbar-inverse navbar-fixed-top">
<ul class="nav nav-pills">
<li>{{#link-to "myleaves" myLeaves action="myleavesinfolist"}}My Leaves{{/link-to}}</li>
<li>{{#link-to "approvalrequests" approvalRequests action="appreqlist"}}Approval Requests{{/link-to}}</li>
</ul>
<p class="navbar-text navbar-right"><button type="button" class="btn btn-info" {{action "logout"}}>Logout</button></p>
<p class="navbar-text navbar-right"><font color="white" size=4>Welcome {{model.userName}}</font></p>
</div>
{{outlet}}
</script>
EDIT
Based on your model code—and the fact that your requests don’t actually depend on the ID—I’d suggest the following:
App.Router.map(function () {
this.resource('signin', { path: '/' });
this.resource('links', { path: '/links' }, function() {
this.resource('my-leaves', { path: '/myleaves' });
this.resource('approval-requests', { path: '/appreq' });
});
});
function getJSONByPost(url) {
return $.ajax({
url: url,
type: 'POST',
dataType: 'json'
});
}
App.MyLeavesRoute = Ember.Route.extend({
model: function() {
return getJSONByPost('/myleaves');
}
});
App.ApprovalRequestsRoute = Ember.Route.extend({
model: function() {
return getJSONByPost('/aprreq');
}
});
Your template becomes:
<script type="text/x-handlebars" id="links">
<div class="navbar navbar-inverse navbar-fixed-top">
<ul class="nav nav-pills">
<li>{{#link-to "my-leaves"}}My Leaves{{/link-to}}</li>
<li>{{#link-to "approval-requests"}}Approval Requests{{/link-to}}</li>
</ul>
<p class="navbar-text navbar-right"><button type="button" class="btn btn-info" {{action "logout"}}>Logout</button></p>
<p class="navbar-text navbar-right"><font color="white" size=4>Welcome {{userName}}</font></p>
</div>
{{outlet}}
</script>
This is a bit of a departure from what you currently have. It’s hard to know the full structure and flow of your app without speaking directly. Nevertheless, I hope it’s of some use.

Ember.js accessing and changing variables between controllers

I am attempting to write a login/logout widget with ember. I want to toggle the isLoggedIn property such that when a user logs out it is set to False and, True when a user logs in. isLoggedIn is defined in my application controller and called with handlebars in my application template. For now, I need to set the value of of isLoggedIn to true when a user logs in successfully and the Login function is activated inside of LoginController - and logout when the user clicks logout. So my question is: how can I have LoginController & application controller access each other and change variables within them.
Here is some code from the application template:
<section class="top-bar-section">
<!-- Right Nav Section -->
<ul class="right">
...
{{#if isLoggedIn}}
<li><a href="#" {{ action "logout" }}>Logout</a></li>
{{else}}
<li>
{{#linkTo "login"}}Login{{/linkTo}} </li>
{{/if}}
</ul>
</section>
</nav>
{{outlet}}
application controller:
var App;
App = require('app');
module.exports = App.ApplicationController = Ember.ObjectController.extend({
isLoggedIn: false,
logout: function(){
this.set("isLoggedIn", false);
console.log(this.token);
}
});
login template:
...
<form class="form-horizontal" {{action "login" on="submit"}}>
...
<div class="row">
<div class="large-5 columns">
<label>Username</label>
{{input value=username type="text" placeholder="Username"}}
</div>
<div class="large-5 columns">
<label>Password</label>
{{input value=password type="password" placeholder="Password"}}
</div>
<div class="large-2 columns">
</br>
{{input class="small button" type="submit" value="Log In"}}
</div>
</div>
</form>
{{#if errorMessage}}
<div class="large-12 columns alert-box alert">{{errorMessage}}</div>
{{/if}}
{{/if}}
LoginController:
var App;
App = require('app');
module.exports = App.LoginController = Ember.ObjectController.extend({
//some variables...
//other functions...
login: function() {
// set isLoggedIn to true here
...}
});
initially the navbar will see that isLoggedIn is false and therefore show Login. Once you successfully login and click submit, an action will fire off and activate login() inside of LoginController. That is where I want to set isLoggedIn to true such that Logout will appear on the navbar.
Have you tried:
module.exports = App.LoginController = Ember.ObjectController.extend({
needs: ['application']
login: function() {
if (authentification sucess) {
this.set('controllers.application.isLoggedIn', true);
} else {
this.set('controllers.application.isLoggedIn', false);
}
}
});
To access other controllers instances, you use the needs property. Each specified controller will be injected in the controllers property. So needs: ['application'], injects the application controller in controllers.applicaiton.

Change a view property from an unrelated controller

I have the following view:
App.MessageTrayView = Bootstrap.AlertMessage.extend({
message: 'This is a message.',
});
Displayed in this template:
<script type="text/x-handlebars" data-template-name="nodes">
<article>
<form class="form-horizontal">
<fieldset>
{{view App.MessageTrayView id="message-tray-view"}}
<div id="legend" class="">
<legend class="">Nodes <span class="badge">{{controllers.nodesIndex.length}} records</span>
<div class="pull-right">
<a {{action destroyAllRecords}}><i class="icon-remove-circle"></i><a/>
{{#linkTo "nodes.new" class="btn btn-primary"}}Add Node{{/linkTo}}
</div>
</legend>
</div>
{{outlet}}
</fieldset>
</form>
</article>
</script>
And this unrelated controller:
App.NodesIndexController = Ember.ArrayController.extend({
destroyAllRecords: function () {
console.log('destroyAllRecords called');
App.MessageTrayView.set('message', 'All nodes have been deleted');
},
});
I want to change the message displayed as soon as the destroyAllRecords is triggered. This is not working (the error message in the console is telling me that I am doing something * very* wrong). How can I change the message property, so that the changes are directly visible on the page?
You can see the code live here
One quick way of doing this could be to define a property on the App namespace:
App = Ember.Application.create({
messageTrayContent: ''
});
then bind to it in your view using the suffix Binding after your property name:
App.MessageTrayView = Bootstrap.AlertMessage.extend({
messageBinding: 'App.messageTrayContent'
});
Now doing:
App.NodesIndexController = Ember.ArrayController.extend({
destroyAllRecords: function () {
console.log('destroyAllRecords called');
App.set('messageTrayContent', 'All nodes have been deleted');
},
});
should work.
Hope it helps.

EmberJS: How to update model attributes

I've got a list of messages that are provided by a Rails backend. What I need is when the "toggle_visibility" action button is pressed, it would toggle the "publicly_viewable" property. This means, making a corresponding REST call (to effect the database) and changing the state of the corresponding cached message. Here is where I'm at so far.
Here's what I've got so far, that manages to end up on the debug console:
# app.js
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.extend({
url: 'http://localhost:3000'
})
});
App.Message = DS.Model.extend({
body: DS.attr('string'),
mobile_number: DS.attr('string'),
publicly_viewable: DS.attr('boolean'),
created_at: DS.attr('date')
});
App.Router.map(function() {
this.resource('messages');
});
App.MessagesRoute = Ember.Route.extend({
model: function() { return App.Message.find() }
});
App.MessagesController = Ember.ArrayController.extend({
toggle_visibility: function(){
debugger;
}
});
# index.html
{{#each model}}
<button class="close" {{action toggle_visibility this}}><i class="icon-eye-close"></i></button>
<p class="message_body lead">{{body}}</p>
<small class="source_number">from {{mobile_number}}, received {{date created_at}}</small>
{{/each}}
I've been spending the past few hours reading through the Ember Guides and while I've gotten an idea on what the different classes there are, I still can't visualize clearly how to go about it. Particularly, I'm not sure if this should be a route concern or a controller, and I know that if ever it was a controller responsibility, I know that it should be on an ObjectController but I've been having trouble making it work.
You can use ArrayController#itemController and define a controller for the individual record in your ModelArray. Then you have to specify in the Array Controller the Object Controller responsible for a single object, which you have to reference as well in Handlebars. You can do something like this:
JS:
App.MessageController = Ember.ObjectController.extend({
visibilityClass: function() {
var visibility = this.get('model.publiclyViewable');
return 'toggle-visibility mdi-action-visibility%#'.fmt(
visibility ? '':'-off'
);
}.property('model.publiclyViewable'),
actions: {
toggleVisibility: function() {
var model = this.get('model');
model.toggleProperty('publiclyViewable');
model.save();
}
}
});
Handlebars:
<script type="text/x-handlebars" data-template-name="messages">
<!--
At this point the {{each}} helper will know how to lookup for
the controller simply by it's name
-->
{{#each model itemController="message"}}
<div class="panel panel-primary">
<div class="panel-heading">
<div class="pull-left">
<h3 class="panel-title">{{title}}</h3>
</div>
<div class="pull-right">
<a {{action 'toggleVisibility'}}>
<i class={{visibilityClass}} style="color: #FFF"></i>
</a>
</div>
</div>
<div class="panel-body">
{{body}}
</div>
<div class="panel-footer">
<i class="mdi-communication-quick-contacts-dialer"></i> {{mobileNumber}}
<i class="mdi-notification-event-note"></i> {{createdAt}}
</div>
</div>
{{/each}}
</script>
(see fiddle)
Note: Updated to Ember 1.11.x-beta and changed the code a little bit