change controller property from another controller - ember.js

I have an application that has a Navigation bar that I have put in "Application" context. By default, these Navigation bar links will be disabled and will be enabled only on a particular action from template.
The Application controller that contains the disabled status of the link in Nav Bar:-
App.ApplicationController = Ember.Controller.extend({
userName:"TestUser",
firstLinkDisabled:true,
actions:{
handleToggle:function(){
console.log("Handling application action with linkstatus="+this.firstLinkDisabled);
//this.set("firstLinkDisabled",false);
this.toggleProperty("firstLinkDisabled");
}
}
})
The Index Controller that will send the action to Application Controller:-
App.IndexController = Ember.Controller.extend({
actions:{
toggleApplicationButton:function(){
this.controllerFor("Application").send("handleToggle");
}
}
})
Application Template:
<script type="text/x-handlebars">
{{#link-to 'first' disabled=firstLinkDisabled}}First link in application{{/link-to}}
<button {{action 'handleToggle'}}>Toggle Application Menu </button>
{{outlet}}
</script>
Index Template
<script type="text/x-handlebars" id="index">
<button {{action 'toggleApplicationButton'}}>Toggle Application Menu </button>
</script>
When I click on "Toggle Application Menu" button I get the following output in console.
Console Output
But in Ember inspector the property "firstLinkDisabled" doesn't change. Image of Ember Inspector:-
Ember Inspector Image
The link remains disabled.
What am I doing wrong here?
Doesn't ember allow to change the property of other controller?
How to make this thing work?

Here is a simple example from my project:
import Ember from 'ember';
export default Ember.Controller.extend({
/*first, inject a controller*/
loginController: Ember.inject.controller('lang.login'),
/*some code*/
actions: {
register: function () {
/*some code*/
/*work with injected controller*/
var c = this.get('loginController');
c.set('identification', that.get('user').email);
c.set('password', that.get('user').plainPassword);
/*some code*/
}
}
});
ember docs

Use Ember.inject.controller()
App.IndexController = Ember.Controller.extend({
appController: Ember.inject.controller("Application"),
actions:{
toggleApplicationButton:function(){
this.get("appController").send('handleToggle');
}
}
})
controllerFor you can use in the Routes
Also you can use the alias
appController: Ember.computed.alias('controllers.Application')
Refer Emberjs official documentation for detail

First, inject the application controller into the index controller
//index.js
application: Ember.inject.controller(),
Then you can access the property in the application controller like this:
//index.js
application.toggleProperty("firstLinkDisabled");

Related

"Application Actions" in Ember 2.1

I'm trying to create a modal for my users to signin, so I have this link:
<li><a {{action "signin"}}>Sign In</a></li>
in a {{planhw-navbar}} component.
{{planhw-navbar signin=(action "showModal" name="signin-modal")}}
But when I open my browser, I get the error:
An action named 'showModal' was not found in (generated application controller)
I've tried putting an action in a controller, a route, and a component:
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
showModal: function(name) {
this.render(name, {
into: 'application',
outlet: 'modal'
});
}, //...
}
})
My component, {{signin-modal}}, works correctly.
My entire application.hbs:
{{planhw-navbar signin=(action "showModal" name="signin-modal")}}
{{outlet}}
{{outlet 'modal'}}
You need to add an action called showModal in your application.js controller.

observer fire action to early. before action is initialize observes fired the action

Template
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{input type="text" value=model.name}}
</ul>
<p {{action 'test'}}>test</p>
</script>
ember code
App = Ember.Application.create();
App.Router.map(function () {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function () {
return Ember.Object.create({name:'dilip'});
},
actions:{
test:function(){
alert('route test');
console.log('test')
}
}
});
App.IndexController = Ember.Controller.extend({
handleChange:function()
{
console.log('handle')
this.send('test')
}.observes('model.name')
})
action 'test' is already defined in route but its showing below error.This error comes only when i am using observes.
Error while loading route: Error: Nothing handled the action 'test'.
The observer does fires before the route is ready to handle the action. This kinda, sorta makes sense because the controller is "built" as part of the route. I've solved this by setting a property within the routes setupController hook to let the controller know that it's ready for action!
// Route
setupController: function(controller, model) {
this._super(controller, model);
controller.set('routeIsReadyForAction', true);
}
// Controller
routeIsReadyForAction: false,
someObserver: function() {
if (!this.get('routeIsReadyForAction')) {
return;
}
this.send('someRouteAction');
}.observes('someProperty'),
You need to handle the action in the controller, not in the route. Check out this jsbin: http://emberjs.jsbin.com/yubowi/edit?html,js,output
You should define your action within controller.
this.send('test') Looks for actions in this extended class (in this case controller). If u make this.sendAction('test') It goes out and looks for actions but these have to be predefined like so `actionName="actionName". This is mostly used when you have a component that needs to interact with a controller
{{my-component actionName="actionName"}} < sendAction now looks for controllers action

Access jquery event from ember component action

I'm trying to work with a simple overlay component, and close this overlay if someone clicks outside of the overlay content:
<div class="overlay" {{action 'close' on='click'}}>
<div class="item">
<form {{action 'submit' on='submit'}}>
{{yield}}
{{#link-to closeRoute class="close"}}Close{{/link-to}}
</form>
</div>
</div>
The component looks like this:
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
submit: function() {
this.sendAction();
},
close: function(param) {
console.log(param); // -> undefined
console.log(this); // -> complete component object, no reference to the event?
// this.$("a.close").click();
}
}
});
This works like advertised, however, I need to determine the target of the click event, because also clicks on the item and form will trigger this click(close) action.
Question: How can I access the (jQuery) event object which has a target from within the close action inside the component?
I am using EmberCLI, and Ember 1.9
I have found this to provide the required result:
export default Ember.Component.extend({
classNames: ['overlay-block'],
didInsertElement: function() {
var self = this;
self.$().click(function(e) {
if (self.$(e.target).hasClass("overlay-block")) {
self.$("a.close").click();
}
});
}
});
This does not use an ember action like I expected. I'll leave the question open for a while to see if somebody comes up with an more 'Ember way' of doing this.
More Ember way
export default Ember.Component.extend({
classNames: ['overlay-block'],
click: function(e) {
if (this.$(e.target).hasClass("overlay-block")){
this.$("a.close").click();
}
}
});

Evaluating controller property everytime the template is rendered in Ember

I have a template called sample and I am changing the property show in the controller based on a button press. Now I want the controller to reset the property every time the template is rendered. Currently even if I go to 'next' template and come back, the property show remains true if the button on sample was pressed. I want to change this behaviour and the property show should be false by default. I know I can do this by defining a view and using the didInsertElement hook but is that the only way to do this?? Ember.js website says that Views in Ember.js are typically only created for the following reasons:
When you need sophisticated handling of user events
When you want to create a re-usable component
and I am doing none of the above. Here is some sample code:
<script type="text/x-handlebars" data-template-name="sample">
{{#if show}}
Showing stuff
{{/if}}
<button {{action changeShow}}>Change</button>
{{#link-to 'next'}} Next {{/link-to}}
</script>
<script type="text/x-handlebars" data-template-name="next">
Hello
{{#link-to 'sample'}}Back{{/link-to}}
</script>
App.SampleController=Ember.Controllers.Extend{(
show:false,
actions:{
changeShow:function(){
this.controllerFor('sample').set('show',true);
}
}
)};
you can use didTransition action which will trigger automatically once the transition happened. didTransition action
App.SampleController=Ember.Controllers.Extend{(
show:false,
actions:{
didTransition:function(){
this.controllerFor('sample').set('show',false);
},
changeShow:function(){
this.controllerFor('sample').set('show',true);
}
}
)};
You can use the renderTemplate hook for the route you're doing this in, and change the controller variable in there.
http://emberjs.com/api/classes/Ember.Route.html#method_renderTemplate
I'd do something like this:
App.PostsRoute = Ember.Route.extend({
renderTemplate: function(controller, model) {
var favController = this.controllerFor('favoritePost');
favController.set("toggle", false)
this._super()
}
});

{{action}} with a click event doesn't trigger the function in the v2 Ember router

I just updated Ember and I am trying to convert an old app to the new router API.
In my template I have this:
<button {{ action "createNewApp" }} class="btn btn-primary">Create application</button>
And I put a createNewApp in my route:
App.CreateAppRoute = Ember.Route.extend({
renderTemplates: function() {
this.render({ outlet: 'content'});
},
createNewApp: function(){
console.log("It's clicked");
}
});
However, when I click on the button the function is never called. I have tried to change the target of the event to the controller but it's still not working. Is this a bug or am I doing something wrong?
I was able to handle the click using a function in the events property of the router (thanks sly7_7) or using a function in the controller:
Template:
<script type="text/x-handlebars" data-template-name="application">
<h1>Content Here:</h1>
{{outlet content}}
</script>
<script type="text/x-handlebars" data-template-name="content-view">
<h2>content</h2>
<button {{ action "createNewApp" }} class="btn btn-primary">Create application</button>
</script>
JS:
var App = Ember.Application.create();
App.CreateAppView = Ember.View.extend({
templateName: "content-view"
});
App.CreateAppController = Ember.Controller.extend({
createNewApp: function(){
console.log("It's clicked, controller");
}
});
App.Router.map(function(match) {
match('/').to('createApp');
});
App.CreateAppRoute = Ember.Route.extend({
renderTemplates: function() {
this.render({ outlet: 'content'});
},
events: {
createNewApp: function(){
console.log("It's clicked, router");
}
}
});
When the button is clicked, the console log message is "It's clicked, controller" and when the function in the controller is removed the action is handled by the router, and the console log message is "It's clicked, router". If no target is specified in the {{action}} Ember tries to find the event in the view, then the controller, then the route.
This is using a build of emberjs built today from source.
Original answer below:
The {{action}} in the new router is replaced with {{linkTo}}.
The emberjs.com guides are constantly being updated with new info about the new router. The links guide covers the {{linkTo}} helper, and the actions guide discusses using the {{action}} helper to handle events in templates.