Mocking models for testing Ember.easyForms input component inside another ember component - ember.js

I am using ember-cli qunit testing using moduleForComponent. I have the following select element inside an ember component I have created.
{{input site as="select"
collection="sites"
selection="site"
optionLabelPath="content.siteLabel"
optionValuePath="content.id"
prompt="Please Select"
label=" "
}}
The actual sites collection is found using the store.
sites : function() {
return this.get('store').find('site');
}.property()
I am using jsMockito to mock out the store.
var siteMock = mock(DS.Model);
when(siteMock).get('id').thenReturn(1);
when(siteMock).get('siteLabel').thenReturn('Qunit');
var storeMock = mock(DS.Store);
when(storeMock).find('site').thenReturn([siteMock]);
I pass this into the components as a parameter in the test.
var component = this.subject({
store : storeMock
});
The generated html looks like this, it seems that siteMock has rendered but the optionLabelPath and optionValuPath did not work correctly even though I have added the appropriate expectations on the mock.
<select id="ember473" class="ember-view ember-select">
<option value="">Please Select</option>
<option id="ember491" class="ember-view" value=""></option>
</select>
I have tested using the getters on the siteMock in the debugger and everything is working as expected. I guess I need another when condition on some property of siteMock but I am not sure what. Can anyone give me some advice on getting this working?

The problem seems to be that you are using content. in your paths optionLabelPath="content.siteLabel" which is thinking about controller proxing to a model.
But your test are using the models directly -undecorated by a controller- and they do not have a content property.

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).

Ember unable to retain dropdown value

I am using Ember 2.5.0. In my application, I have created a page with a dropdown using the ember-select-list plugin.
I am able to render the dropdown, but unable to retain the value of the dropdown. Whenever I select the value, I am getting the following exception in the chrome console:
Assertion Failed: Cannot call get with 'id' on an undefined object
Please find the following code, for reference:
Template :
{{select-list content=roles
optionValuePath="role"
optionLabelPath="role"
value=role
action=(action (mut role))}}
Route.js
export default Ember.Route.extend({
model(){
return Ember.RSVP.hash({
books : this.store.findAll("book"),
roles : this.store.findAll("role")
});
},
setupController(controller,model){
controller.set('users',model.books);
controller.set('roles',model.roles);
}
});
Model
export default DS.Model.extend({
role:DS.attr()
});
In the router, when I pass Array(roles: this.store.findAll("role").toArray()) instead of model, I can retain the value, but it throws an error while passing model.
Anyone, could you please help me to resolve this issue?
The ember-select-list documentation and unit test indicate that an array is required for the content property on the {{select-list}} helper.
This is why Ember.RSVP.hash seems to fail, as hash expects and returns an object, which is a type that ember-select-list is not configured to use.
Instead of hash, you should use Ember.RSVP.all, as all expects and returns an array, which should work.
I've created an Ember Twiddle example to demonstrate.
If you'd rather not use ember-select-list, you might find it easier to merely use Ember's each helper to build out your own select list, like this:
<select onchange={{action "selectRole" value="target.value"}}>
{{#each roles as |role| }}
<option value="{{ role }}" label={{ role }}>
{{ role }}
</option>
{{/each}}
</select>
I would suggest you use ember-power-select addon.
To your question, you can try this,
setupController(controller,model){
controller.set('users',model.books);
controller.set('roles',model.roles.toArray());
}
let me know if this is not working

Accessing model data in router when using a view

I am looking for a way to access model data in a route when using a view to display model attributes.
Example
Template
<h2>New post</h2>
<form {{action save model on="submit"}}>
<label>Title</label>
{{input type="text" value=title placeholder="title" id="title"}}
<label>Text</label>
{{view "tinymce" value=text }}
<button>Post</button>
</form>
View Template
<textarea id="tinymce">
</textarea>
View
export default Ember.View.extend({
templateName: 'views/tinymce-textarea',
didInsertElement: function() {
tinymce.EditorManager.execCommand('mceRemoveEditor',true, 'tinymce');
tinymce.EditorManager.execCommand('mceAddEditor',true, 'tinymce');
}
});
Router
export default Ember.Route.extend({
....
actions : {
save : function(model) {
if (!model.get('title').trim() || !model.get('text').trim()) {
return;
}
model.save().then(this.onSuccessfulSave.bind(this), this.onFailedSave.bind(this));
}
}
});
Now, obviously this doesn't work, since model.text is never bound in the view, like it would be if I were to use the textarea template helper:
{{textarea value=text placeholder="text" id="text"}}
But this is just one of many (many) ways I have tried to get this to work, and I am at a complete loss as how one would access model attributes in the route when using a view. And it does seem like a pretty common usecase to me too.
I have failed to find information regarding this on SO or anywhere else, so if anyone is able to help me, thanks in advance! / AS.
So one of the main things that you're missing out is binding the view to the controller. This is actually really straight forward to do, but without it Ember doesn't know that it should propagate changes between the two. The first thing I would do is this:
{{view "tinymce" valueBinding="text" }}
This says that the views value will be binded to the controller's text value. Whenever view's value is updated, it will propogate to the controller and vice versa.
The next item to take care of is actually binding the value in the view. All you need to do is tell the input to bind it's value to the view's value. This can be done like this
{{textarea value="view.value" placeholder="text" id="text"}}
Try this out, and you can use this jsbin that I created as an example:
http://emberjs.jsbin.com/qanudu/26/
If you have any other questions just let me know, but this should solve your issues!

Ember Data belongsTo with Select dropdown view

I am trying to do something pretty basic with Ember and Ember Data.
1) Posts belongsTo Users; Users hasMany Posts
2) In the create new Post form, I want to have a select/dropdown of all Users
3) When I edit a post (using the same form), I want to bind it correctly back to the dropbox
Question: What is the best practice to do the dropdown that binds to the list of users?
How can I bind the edit form to populate the dropdown again?
User Model:
App.User = DS.Model.extend({
posts: DS.hasMany('post', {async: true}),
});
Post Model:
App.Post = DS.Model.extend(Ember.Validations.Mixin, {
user: DS.belongsTo('user', {async: true}),
});
Create New Post Form:
{{view Em.Select
content=users <<<<< How do I bind this.store.find("user") here?
optionValuePath='content.id'
optionLabelPath='content.name'
}}
I don't understand the best practice to bind the select content with users.
Attempt 1:
*I am using Ember-Form
{{em-select
property="user_id"
label="user"
prompt="Select user:"
content=controllers.users.content
optionValuePath="content.id"
optionLabelPath="content.first_name"
}}
And on the save action:
newItem.set('user', this.store.getById('user', this.get('user_id')));
I tried to use user_id as my property for the form, and translate back to a user object to assign to the post when I save. However, this method is kind of stupid because I am actively translating user_id to user object every time I save. I feel like there should be a way that that is done automatically if I did the correct binding, instead of jumping through hoops to bind the property as user_id. This also makes it hard for me to bind back when I use the same form for editing the post. Since all the relationship has been setup, I have a feeling that I am doing something wrong here. I think there must be a better way.
Thanks!
As of September 2014 there is an issue with Ember.Select plus { async: true }. They don't play well together.
myModel.get('myAsyncRel') will return a promise, Ember.Select is not promise aware, so it cannot handle this properly.
One workaround is to use a non-async relationship.
https://github.com/emberjs/data/issues/1405
https://github.com/emberjs/data/issues/2111
Another workaround is to use something like this:
http://emberjs.jsbin.com/rwjblue/43/edit?html,css,js,output
The ember team has opened an issue (#5259) for this problem, they are planning to rewrite the whole Ember.Select part.
In the meantime you can use this Add-on from thefrontside:
{{#x-select value=bob action="selectPerson"}}
{{#x-option value=fred}}Fred Flintstone{{/x-option}}
{{#x-option value=bob}}Bob Newhart{{/x-option}}
{{/x-select}}
Install it with ember install emberx-select
EDIT As Stefan Penner wrote, you can now use the ember select as follows (jsbin):
<select onchange={{action "changed" value="target.value"}}>
{{#each model.choices key="#identity" as |choice|}}
<option value={{choice}} selected={{is-equal currentValue choice}}>{{choice}}</option>
{{/each}}
</select>
When you say dropdown I presume you mean a select box? Ember's API has a select view that handles all of the data binding. Here are the docs for Ember.Select.
You can use it in your post form like so:
{{view Em.Select
content=users
selection=user
optionValuePath='content.id'
optionLabelPath='content.name'
}}
If you're using Dockyard's awesome ember-easyForm library you can utilize an Em.Select like this:
{{input user type='as'
collection='users'
selection='user'
optionValuePath='content.id'
optionLabelPath='content.name'
prompt='Choose type...'
}}
Advanced UI using Chosen can be easily integrated with Ember like this.
New deprecation information was added in Ember 1.13 for Ember Select, see http://emberjs.com/deprecations/v1.x/#toc_ember-select.
The new recommended approach in Ember 1.13/2.0 is to implement a component yourself:
e.g.
/components/my-select.hbs
<select>
{{#each users "id" as |user|}}
{{log address}}
<option value="{{user.id}}">
user.name
</option>
{{/each}}
</select>
The ember link shows how to implement selection with selected={{is-equal item selectedValue}} and creation of a is-equal helper.

Calling an action within controller in Ember

I am getting some data from server and in my controller I am trying to display that in list format. What I want to do is to allow the user to click on any item of that list and call an action behind it. Here is my js code.
for(var index in posts) {
if (posts.hasOwnProperty(index)) {
console.log(1);
var attr = posts[index];
//console.log(attr);
/*$("ul#previous_recipients").append('<li class="list-group-item"><label>'+attr.name+'' +
'</label><a href="javascript:void(0)" class="close g-green" {{action "aa"}}>Add</a></li>');*/
$("ul#previous_recipients").append(Ember.Handlebars.compile('<li class="list-group-item"><label>{{attr.name}} </label>Add</li>'));
}
}
How to call action on it? {{action "test"}} is not being called.
You have to compile the handlebars template and define the test action inside actions hash in the same controller.
$("ul#previous_recipients").append(Ember.Handlebars.compile('
<li class="list-group-item"><label>{{attr.name}} </label>
Add</li>
'));
You have to move this html code from controller to a handlebars file,that will be good.
What you need to do is create an ember view and give it a
templateName
property which will contain your html and handlebars expression. Alternately, you could, inside the view say
defaultTemplate: Em.Handlebars.compile(/*your handlebars and html markup here*/)
using Jquery to do things like this is not the ember way of doing things.