Ember.js this.set() not working from inside action - ember.js

Folks, I'm having some beginner problem and would love some assistance. This is in ember 2.6 if it makes any difference. Basically, I'm trying to change some text on the screen when the button is pressed inside a component. Here's the handlebars and component js code:
<h2>Stupid Button</h2>
<div>
<form id="sign_in_form" {{action 'triggerTheAction' on='submit'}}>
<button id="signin" type="submit">FIRE!</button>
{{someTextThatShouldChange}}
</form>
</div>
And the component's js code:
export default Ember.Component.extend({
someTextThatShouldChange: 'Initial Value',
actions: {
triggerTheAction: (email, password) => {
alert('alerts just fine');
this.set('someTextThatShouldChange', 'New value for text!');
}
}
});
The error I get in console:
TypeError: _this.set is not a function
Really appreciate the help. I have a feeling I'm just not understanding something fundamental about Ember.

You are using an arrow function to define the action handler. This means that it's binding this to the outer scope, which in your case is the ES6 module. By the specification, a module's this is undefined.

Related

how to trigger a function automatically in ember.js action helper?

I am new to ember.js and working on an application to highlight text like below:
<div>
<h3 class = "title" {{action "highlight" "title"}}>{{document.title}}</h3>
<div class = "date" {{action "highlight" "date"}}>{{document.date}}</div>
<p class = "content" {{action "highlight" "content"}}>{{document.contents}}
</p>
</div>
I created a function highlight which will get the class name and highlight the search text the user input. This function works fine, but I have to click to trigger this highlight function. Is there any way in ember action helper can trigger this function whenever the div node rendered or automatically triggered?
What you probably need is to implement the hook didInsertElement, this will trigger as soon your component got rendered in the screen.
Example:
import Component from '#ember/component';
export default Component.extend({
didInsertElement() {
this._super(...arguments);
const title = this.element.querySelector('.title');
// do something with the title
},
});
More information about didInsertElement can be found in this guide: https://guides.emberjs.com/v2.18.0/components/the-component-lifecycle/
I don't understand your use-case entirely, but I think actions are not a good choice for your problem. I would recommend reading the ember guides about computed properties. These properties are recomputed everytime an underlying property changes.
highlightedContent: computed('userInput', 'content', function() {
....
//return computedContent;
})
I would also recommend reading the guides about handlebar-helpers. You could write a highlight-helper.

How to create action for my own component

I am creating one ember app.
Flow is like " page1 displays list of feeds item and clicking on any of the feed will take user to page2 showing details about that feed"
What i am doing:
i have one component named app-feed. Template is as below
<div onclick={{action 'click' feed}}>
{{#paper-card class="card-small" as |card|}}
<!-- --> {{card.image src=feed.imagePath class="small-feed-img" alt=feed.title}}<!---->
{{#card.header class="flex-box short-padding" as |header|}}
{{#header.avatar}}
<img class="profile-small" src="http://app.com/users/{{feed.userName}}.jpg" alt="{{feed.name}}" />
{{/header.avatar}}
<span class="tag-sm like-box">
{{feed.likes}} {{paper-icon "thumb_up" size="18"}}
{{feed.commentCount}}{{paper-icon "chat_bubble" size="18"}}
</span>
{{/card.header}}
{{#card.actions class="action-block"}}
{{#paper-button iconButton=true}}{{paper-icon "favorite" size="18"}}{{/paper-button}}
{{#paper-button iconButton=true}}{{paper-icon "share" size="18"}}{{/paper-button}}
{{#paper-button iconButton=true}}{{paper-icon "shopping_basket" size="18"}}{{/paper-button}}
{{/card.actions}}
{{/paper-card}}
</div>
component.js is as below
import Ember from 'ember';
export default Ember.Component.extend({
actions:{
click(feed){
console.log("Click event fired:"+feed.id); //Output is correct in console
this.sendAction("onClick", feed); //sending onClick Action
}
}
});
I'm populating list of this component in one of my route.
Template is as below
{{#app-sidenav user=model}}{{/app-sidenav}}
<div class="content">
<div class="row">
{{#each model as |item|}}
{{#app-feed-small onClick=(action "getDetail" item) class="col-xs-5" feed=item}} {{/app-feed-small}}
{{/each}}
</div>
</div>
route.js is as below
import Ember from 'ember';
export default Ember.Route.extend({
store: Ember.inject.service(),
model(){
//Populating module. Works just fine
} ,
actions:{
getDetails(feed){
console.log("Getting details of "+feed.id);
}
}
});
I have defined getDetails action as mentioned in my template.js of the route still i am getting below error
""Assertion Failed: An action named 'getDetail' was not found in (generated feed.index controller)""
feed.index is my route.
I used same method and modified paper-chip's source to get action corresponding to click on paper-chip's item which worked. But i am not able to do same in my own component.
Please let me know what is missing
Your problem is that in your second last code snippet, the one with your template. You refer to the action as getDetail but in route.js your last code snippet you declare the action as getDetails which is different to the code in your template. It's a common spelling error, one has an "s" st the end whereas the other doesn't.
The actions should be in controllers. And if controller bubbles up then the action in route be called.
For your case you don't need controller.
You can use ember-transition-helper
I assume you have in router.js :
this.route('feeds', function(){
this.route('edit', {path: '/:id'});
});
Now your template is going to be :
{#app-sidenav user=model}}{{/app-sidenav}}
<div class="content">
<div class="row">
{{#each model as |item|}}
{{#app-feed-small onClick=(transition-to "feeds.edit" item) class="col-xs-5" feed=item}} {{/app-feed-small}}
{{/each}}
</div>
</div>
sendAction is an ancient way to calling action inside controller/route.
The new style is to use closure action, which passes action as a value by creating a closure at the time of value passing.
Yes, you are correct. The action has been sendAction is able to bubble up from,
correspond controller -> correspond route -> upper route -> ... -> application route
However, closure action does NOT bubble.
Please refer to Ember component send action to route where #kumkanillam detailed explained how to call action inside route using different method and the differences between sendAction and closure action.
I have also made a sample project and write a simple explanation for it at,
https://github.com/li-xinyang/FE_Ember_Closure_Action

link-to action parameters are not working in 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).

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

toastr and ember.js

Is the popup library toastr not going to work with Ember because of direct dom manipulation that ember doesn't like?
Are there any other libraries like this one that work nicely with ember?
Edit
Even through the working example posted below I could not get this to work locally. I finally used Pine Notify which worked straight away.
This works fine in Ember, you just have to handle the event in the right place. The "right place" depends on your implementation. If you want this to be fired from a button within your view, you'll need to use the {{action}} helper passing the action name. Example:
<script type="text/x-handlebars" >
<button class="btn btn-info" {{action showInfo}}>Info</button>
</script>
In the template above, I'm saying that the button should fire the showInfo event, so the Controller responsible for this view should have a function with the same name:
App.ApplicationController = Em.ArrayController.extend({
showInfo: function() {
toastr.info('This is some sample information');
}
});
You can also have the view handle the event; the code below defines a click event, so if you click anywhere in the view, it would run your function:
App.OtherView = Em.View.extend({
click: function(e) {
toastr.error('This is some sample error');
}
});
and in your Handlebars template, you don't have do tell the action since you are already saying in the view class that you want to handle the click event for that view, so you can simple render the view and style it:
{{#view App.OtherView class="btn btn-danger"}}
Error
{{/view}}
Here's a sample in JSFiddle: http://jsfiddle.net/schawaska/YZwDh/
I recommend that you read the Ember Guide about the {{action}} helper