link-to action parameters are not working in ember js - ember.js

Hi i am very new to ember js. i pass action parameters(id ) on link-to action in template but i did not get the values in my controller.
My Template code as follows:
index.html:
<script type="text/x-handlebars" data-template-name="search">
{{#each model.results}}
// here i pass id value along with action
{{#link-to 'profile' id action="profileinfo"}}
</script>
app.js:
App.SearchController = Ember.ObjectController.extend({
id: '',
actions:{
profileinfo: function(id){
// Here i access id value like this
console.log(id);
var id = this.get('id');})
when i click on the link action goes to Searchcontroller, but i get id value is empty.I follow some solutions in stack overflow but unfortunately i did not get anything. Please provide some solution

I don't get why you're using the {{#link-to}} helper for triggering an action on your controller. Maybe you could simply use the {{action}} helper ?
If you try doing it that way, would it work ?
<button type="button" {{action "profileinfo" id}}>Click me !</button>
From there, your console.log(id); should get your value.
EDIT
Would also work for a <a> tag
<a href="#" {{action "profileinfo" id}}>Click me !</a>

I've created popular addon for doing just that:
{{#link-to 'profile' id invokeAction='profileinfo'}}
Simply install it:
ember installember-link-action
Please leave a star if you enjoy it or leave feedback if you feel anything is missing. :) It works with Ember 1.13 and 2.X (tested on Travis CI).

Related

How to programatically add component via controller action in Ember 3.x

I want to add add multiple copies of a component via js and pass different params in it. The code should execute via controller action of click on a button in the template. The solution for 2.x doesn't work in Ember version 3.x(pre-octane). Can anybody please help. I can't render plain html as I am using other addon of ember in the component.
Basically you want an array with the params in the js, and then a {{#each loop invoking the components. Something like this:
#tracked componentParams = new TrackedArray();
#action showThem() {
this.componentParams.push({ value="foo" });
this.componentParams.push({ value="bar" });
this.componentParams.push({ value="baz" });
}
{{#each this.componentParams as |params|}}
<MyComponent #value={{params.value}} />
{{/each}}
<button type="button" {{on "click" this.showThem}}>Show Them</button>
(this uses TrackedArray from tracked-built-ins).

How can I add a class in ember js

<script type="text/x-handlebars">
<div class="wrapper">
<div class="sideMenu">
{{#link-to 'home'}}Home{{/link-to}}
{{#link-to 'posts'}}Posts{{/link-to}}
</div>
<div class="content">
{{outlet}}
</div>
</div>
</script>
I am new to ember js. How can I add a class on 'content' class each time when view changes.
We do something like this:
Ember.Route.reopen({
activate: function() {
var cssClass = this.toCssClass();
// you probably don't need the application class
// to be added to the body
if (cssClass !== 'application') {
Ember.$('body').addClass(cssClass);
}
},
deactivate: function() {
Ember.$('body').removeClass(this.toCssClass());
},
toCssClass: function() {
return this.routeName.replace(/\./g, '-').dasherize();
}
});
It would add a class to the body (in your case just use content), that is the same as the current route.
#torazaburo had some excellent points about #Asgaroth (accepted) answer, but I liked the idea of not having to write this same functionality over and over again. So, what I am providing below is a hybrid of the two solutions plus my own two cents and I believe it addresses #torazaburo concerns regarding the accepted answer.
Let's start with the 2nd point:
I also don't like the idea of polluting Ember.Route
Can you pollute Ember.Route without polluting Ember.Route? (Huh?) Absolutely! :) Instead of overwriting activate, we can write our own function and tell it to run .on(activate) This way, our logic is run, but we are not messing with the built-in/inherited activate hook.
The accepted answer is very procedural, imperative, jQuery-ish, and un-Ember-like.
I have to agree with this as well. In the accepted answer, we are abandoning Ember's data binding approach and instead fall back on the jQuery. Not only that, we then have to have more code in the deactivate to "clean up the mess".
So, here is my approach:
Ember.Route.reopen({
setContentClass: function(){
this.controllerFor('application').set("path", this.routeName.dasherize());
}.on('activate')
});
We add our own method to the Ember.Route class without overwriting activate hook. All the method is doing is setting a path property on the application controller.
Then, inside application template, we can bind to that property:
<div {{bind-attr class=":content path"}}>
{{outlet}}
</div>
Working solution here
Just bind the currentPath property on the application controller to the class of the element in the template:
<div {{bind-attr class=":content currentPath"}}>
{{outlet}}
</div>
In case you're not familiar with the {{bind-attr class= syntax in Ember/Handlebars:
the class name preceded with a colon (:content) is always added to the element
properties such as currentPath result in the current value of that property being inserted as a class, and are kept dynamically updated
To be able to access currentPath in a template being driven by a controller other than the application controller, first add
needs: ['application']
to the controller, which makes the application controller available under the name controllers.application, for use in the bind-attr as follows:
<div {{bind-attr class=":content controllers.application.currentPath"}}>
You may use currentRouteName instead of or in addition to currentPath if that works better for you.
The class name added will be dotted, such as uploads.index. You can refer to that in your CSS by escaping the dot, as in
.uploads\.index { }
Or, if you would prefer dasherized, add a property to give the dasherized path, such as
dasherizedCurrentPath: function() {
return this.('currentPath').replace(/\./g, '-');
}.property('currentPath')
<div {{bind-attr class=":content dasherizedCurrentPath"}}>
This has been tested in recent versions of ember-cli.

Access Controller in a View in a Render

I have a view like this:
App.AbilityFilter = Ember.TextField.extend({
classNames: ['span3'],
keyUp: function(evt) {
this.get('controller').send('filterAbilities','text');
},
placeholder:'Search abilities'
});
It's part of a render like this:
<script type="text/x-handlebars" data-template-name="abilities">
{{view App.AbilityFilter}}
<div class="accordion" id="abilities">
{{#each ability in model}}
<div class="accordion-group">
{{ability.name}}
</div>
{{/each}}
</div>
</script>
Which is being rendered in my application like this:
{{render 'abilities'}}
The problem I'm having is with the event or, rather, the action. The keyUp event fires perfectly well, but for some reason it won't go to a controller.
I've tried adding the filterAbilities to the actions hash on both the App.AbilitiesController and the App.IndexRoute according to this. According to this, the view should be part of the abilities controller since that's the context of it's parent, but it's not working.
I've done some testing and it almost seems like this.get('controller') isn't fetching a controller at all. I'm a bit lost as to what's causing the problem. This code worked a few RCs ago, but as soon as I upgraded to 1.0 it broke.
What I'm trying to do here is filter the list of abilities. If this isn't the way to this anymore, please let me know! Any help would be appreciated. Thanks!!
Ember.TextField and Ember.TextArea are no longer simple views but rather subclasses of Ember.Component which means that this.get('controller') does not refer anymore to the views controller.
But there is a different variable which indeed holds a reference to the surrounding controller and this is this.get('targetObject'). Therefore you should send your action to the targetObject:
App.AbilityFilter = Ember.TextField.extend({
classNames: ['span3'],
keyUp: function(evt) {
this.get('targetObject').send('filterAbilities','text');
},
placeholder:'Search abilities'
});
Hope it helps.

How to trigger an action on a controller from a template

I have this jsbin. My problem is that I am trying to trigger an action:
<a {{action controllers.nodesIndex.destroyAllRecords this}}><i class="icon-remove-circle"></i><a/>
But I get an:
Uncaught Error: Nothing handled the event 'controllers.nodesIndex.destroyAllRecords'
(You can trigger that by pressing the little icon icon-remove-circle on the top-right, and checking the error on the js console)
But my controller is properly set-up:
App.NodesIndexController = Ember.ArrayController.extend({
destroyAllRecords: function () {
console.log('destroyAllRecords called');
},
});
What am I missing here?
Since the controller for the nodes/index template is the App.NodesIndexController, You need to mention it as controllers.nodesIndex.destroyAllRecords, the default target will be App.NodesIndexController, and so you can just say <a {{action destroyAllRecords}}> as #Thomas told.
Also for getting the length of records, just say {{this.length}} instead of {{controllers.nodesIndex.length}}.
I've updated your jsbin,
You'll need to say as 'controllers.controllername.methodname' only if you are referring to some other controller than the controller for the template, and you've to give the controller's name in the needs list,
say, if you want to call a method of your 'profile' route from your 'nodes/index' template,
then
App.NodesIndexController = Ember.ArrayController.extend({
needs: ['profile'],
});
and in your template,
<a {{action controllers.profile.methodname}}>
Hope it helps.
UPDATE: Refer the solution and the bin in the comment

Creating a dynamic string with bindAttr

I'd like to create a dynamic classname on an object with a value I'm getting from my model. One of the keys is named provider which contains either "twitter" or "facebook". What I'd like to do is to prepend the string "icon-" to the provider so that the resulting class is icon-twitter or icon-facebook.
This is the code that I've got now.
<i {{bindAttr class=":avatar-icon account.provider"}}></i>
Ember offers a way to include a static string within the attribute by prepending : to it. You can see that I'm also adding a class called avatar-icon in this example. I've already tried :icon-account.provider which simply resulted in the literal string "icon-account.provider".
RESPONSE
Nice one. I'm working on a solution similar to your answer right now. Question though: this view will be used within the context of an each loop. How would I pass in the current item to be used within the view? I have this right now:
{{#each account in controller}}
{{#view "Social.AccountButtonView"}}
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
Is it possible to just do this:
{{#view "Social.AccountButtonView" account="account"}}
?
I have previously stated that attributeBindings would be a suitable solution for this, but I was mistaken. When binding the class attribute of a given View, as pointed out, you should use classNames or classNameBindings. Please refer to the sample below:
App.ApplicationView = Em.View.extend({
provider: 'Facebook',
classNameBindings: 'providerClass',
providerClass: function() {
return 'icon-avatar icon-%#'.fmt(this.get('provider').toLowerCase());
}.property('provider')
});
This will render the following HTML:
<div id="ember212" class="ember-view icon-avatar icon-facebook">
<h1>App</h1>
</div>
Here's a fiddle: http://jsfiddle.net/schawaska/HH9Sk/
(Note: The fiddle is linking to a version of Ember.js earlier than RC)