Ember unable to retain dropdown value - ember.js

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

Related

Ember JS - Add select box option to URL string via Query Param

I have a Select Box in my form and I would like to be able to use the selection as a Query Param so that I can refresh a model based on its selection. The Select Box is from this ember add-on.
{{#select-box/native value=sb name=module on-select=(action 'selected') class="form-control" as |sb| }}
{{sb.option value='Select a Module:'}} {{sb.option value='Option1'}} {{sb.option value="Option2" }} {{sb.option value="Option3" }} {{sb.option value="option4" }}
{{/select-box/native}}
The 'selected' action simply adds the option to a variable so that I can use it later in a switch statement:
selected(x) {
module = x
},
I'd like to have the selection (or a representation of the selection) in my URL string but I can'tt work out how. I have other inputs building into the URL string but none of them are select boxes.
I have a 'module' item in the QueryParams on my route but it doesn't do anything, I suspect I'll have to do something in the 'selected' action but I'm not sure what.
I haven't used the add-on you mentioned, but here is how you can do it using normal <select>, so just bridge the gap between normal <select> and the add-on you are using in terms of making sure that the status variable in the example below changes depending on what you select in your select box - Ember will do the rest.
Here's a configuration that works if you want to filter a list of users based on the status value you select from a dropdown:
// app/models/user.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
status: DS.attr('string')
});
// app/templates/users.hbs
<select onchange={{action (mut status) value="target.value"}}>
<option value="" selected={{eq status ''}}>- All users -</option>
<option value="active" selected={{eq status 'active'}}>Active</option>
<option value="inactive" selected={{eq status 'inactive'}}>Inactive</option>
</select>
<ul>
{{#each model as |user|}}
<li>{{user.name}}, {{user.status}}</li>
{{/each}}
</ul>
// app/controllers/users.js
import Controller from '#ember/controller';
export default Controller.extend({
queryParams: ['status'],
status: ''
});
// app/routes/users.js
import Route from '#ember/routing/route';
export default Route.extend({
queryParams: {
status: {
refreshModel: true
}
},
model(params) {
var options = {};
if (params.status) {
options.status = params.status;
}
return this.get('store').query('user', options);
}
});
How does it work?
In the controller you define a property status, which you also indicate to be a query parameter (in the URL). Then in the route, you also define status to be a query parameter which refreshes the model. In the model() hook you extract the parameter and use it for Ember Data Store's query() to fetch the model every time you change the value of status. Your route URL will have ?status=... appended to it, and your server will receive a request similar to example.com/api/users?status=.... Of course, you can configure options in the model() hook differently to format the request URL for the server, but I kept it like this for the sake of simplicity.
The only thing that might be confusing is the template file. Apart from the {{eq status '...'}} syntax, which is a truth helper that simply determines whether the option is selected, the rest of the selecting simply aims to change the status variable (explained in depth here).

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

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.

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.

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