Multiple selects instead of multi select in Ember application - javascript

in Ember multiselects can be created using the multiple property of the Ember.Select view (e.g. in this post).
What I want to do is substituting a multiselect with multiple "normal" selects, which are all bound to the same array. Let's say I have two single selects, then both should be bound to an array fooArray. When I select foo in the first select and bar in the second one, then fooArray should be ['foo', 'bar'].
Any ideas on how to do that?
Kind regards,
Marius

You can set a selectionBinding for each select and a computed property taha makes the array... sure there are better ways to do this... it depends of the number of selects you deal with, because, in this example, the returned array is recalculated each time you get it
and this don't scale very well
App.SelectionController = Ember.ObjectController.extend({
select1Value:null,
select2Value:null,
select3Value:null,
selectedArray:function{
return Ember.Array(this.get('select1Value'),this.get('select2Value'),this.get('select2Value'));
}.property('select1Value','select2Value','select3Value')
});
In the view
{{view Ember.Select
contentBinding="YourSelectContent"
selectionBinding="App.SelectionController.select1Value"
[...]
{{view Ember.Select
contentBinding="YourSelectContent"
selectionBinding="App.SelectionController.select2Value"
[...]
{{view Ember.Select
contentBinding="YourSelectContent"
selectionBinding="App.SelectionController.select3Value"
[...]

Related

selected boolean value on angular ng-options

The boolean value assigned to the model doesn't pre-select the corresponding option - shows first an empty option instead:
Select:
<select data-ng-model="scriptData.privacy" data-ng-options="privacyOption.value as privacyOption.label for privacyOption in privacyOptionsSelect track by privacyOption.value"></select>
Options in the controller:
$scope.privacyOptionsSelect=[
{
label:'Registered users only can view this',
value: false
},
{
label:'Anyone with the link can view this',
value: true
}
];
scriptData.privacy is set to false.
You should be careful when using the ngOptions expression with the format:
select as label for value in array
together with track by. This is because track by is applied to the value assigned to your ngModel, so if your selection is in the form privacyOption.value, the track by expression is actually applied to the value. This is the reason it doesn't successfully select the initial value.
To fix this you have two options. You can either just skip track by. This would work:
<select data-ng-model="scriptData.privacy"
data-ng-options="privacyOption.value as privacyOption.label for privacyOption
in privacyOptionsSelect"></select>
Or you could change the select as-expression to select the entire privacyOption-object. This would work as well (note the ngModel-directive changed as well):
<select data-ng-model="scriptData"
data-ng-options="privacyOption as privacyOption.label for privacyOption
in privacyOptionsSelect track by privacyOption.value"></select>
For a full (and probably better) explanation, I recommend the ngOptions documentation.
try ng-repeat instead of ng-options by applying the ng-repeat to option elements inside the select.

Ember 1.13, view lookup

Prior to ember 1.13 i was using
var containerView = Em.View.views[view_id];
to get the ContainerView instance with the view id and manually adding childViews to this container view, which used to work just fine.
As of ember 1.13 this view lookup is not supported. What is the recommended way of doing this?
The problem is there are multiple instances of the same containerView with different id's. So i need to get the right instance of containerView from lookup.
Thanks
Update:
I have a parent (widget) component:
parentComponent.hbs
.....
{{input value=someBinding1 click='showCalendar'}}
{{calendar-component month=month1 disableBefore=disableBefore1}}
{{input value=someBinding2 click='showCalendar'}}
{{calendar-component month=month2 disableBefore=disableBefore2}}
{{input value=someBinding3 click='showCalendar'}}
{{calendar-component month=month3 disableBefore=disableBefore3}}
.....
So essentially i can have multiple date(input) fields which when clicked should show up a calendar component. If i write the code as above it would create 3 (or as many date fields) instances of the calendar component. These number of date fields are dynamic. I did not wanted to create so many calendar components as i see sluggish performance on mobile devices.
So what i did was:
.....
{{input value=someBinding1 click='showCalendar'}}
{{calendar-container-view id='calendarContainerView1'}}
{{input value=someBinding2 click='showCalendar'}}
{{calendar-container-view id='calendarContainerView2'}}
{{input value=someBinding3 click='showCalendar'}}
{{calendar-container-view id='calendarContainerView2'}}
.....
And calendar-container-view had an empty childViews array to start.
When user clicks on input field i get the corresponding containerView instance using Em.View.views[containerViewId] and append the calendar instance to it.
When another input is clicked i remove it from old parent containerView and add it to the new container view.
So there is only one calendar instance created by parentComponent.js and removed and added to container view.
Hope it makes sense. I can create a jsbin if need be.
Thanks a lot!
I think you could operate your logic by model instances instead of views (I mean model concept here, it could be some array of objects or records array).
It's clear you have model (as some array), since you mentioned multiple instances.
You might do:
{{!-- list of input fields --}}
{{#each model as |item|}}
{{item-input-field item=item value=item.someBinding1 clickInput="setCurrentItemWhenInstanceClick"}}
{{/each}}
{{!-- and one calendar-component --}}
{{#if currentItem}}
{{calendar-component item=currentItem month=currentMonth disableBefore=currentDisableBefore}}
{{/if}}
where item-input-field is a component, that extends input and pass it's item up to parent component or controller through action clickInput (action up).
Then setCurrentItemWhenInstanceClick action in parent component (or controller) should set currentItem, currentMonth and currentDisableBefore data (data down to calendar-component), so your calendar-component will be shown.

Ember TextField valueBinding to controller issue

I am using the Twitter typeahead.js plugin. So to use it I am extend Ember's TextField. The plugin all works fine. Now I just want to make the value accessible inside the controller.
When I use the value binding inside the view class, it works fine. Here is the bin example. Here the value gets set initially and updates later. To test the text view type 'aaa'.
App.TypeAhead = Ember.TextField.extend({
classNames: ['cmp-typeahead'],
attributeBindings: ['id','value'],
valueBinding: 'targetObject.airportCode',
....
});
But when I try to set the value binding via the template, it doesn't seem to work. Here is the bin example. To test the text view type 'aaa'.
{{view App.TypeAhead data=airports valueBinding="view.targetObject.airportCode"
id="fromAirportCode"}}
What am I doing wrong?
Since the view helper will keep the current controller, it's as simple as:
{{view App.TypeAhead data=airports valueBinding="airportCode"
id="fromAirportCode"}}
Example: http://emberjs.jsbin.com/ciwiv/1/edit

Ember Select populated by other Ember Select not updating selection binding

I'm new to Ember.js and I'm trying to figure out how Select views bind their selection to the controller. I have this template:
{{view Ember.Select
contentBinding="content"
selectionBinding="selectedCompany"
optionLabelPath="content.name"}}
{{view Ember.Select
contentBinding="selectedCompany.employees"
selectionBinding="selectedEmployee"
optionLabelPath="content.name"}}
Employee: {{selectedEmployee.name}}
Age: {{selectedEmployee.age}}
I find that the second select does update when selectedCompany changes, but I can't reference the values of name or age in selectedEmployee until I change the second select's value to a different value physically.
How do I make it so that the selectedEmployee is set when the first select changes, such that I can use it's value?
For better clarity, I have my working code here.
Changing content of second selectbox does not actualy change its selection. You have to do it manually, for example by adding following method to controller
onChangeCompany : function() {
if (!this.get('selectedCompany.employees').contains(this.get('selectedEmployee'))) {
this.set('selectedEmployee', this.get('selectedCompany.employees').objectAt(0));
}
}.observes('selectedCompany')
It stil needs some non-null and array-range checking, but does the job - if you select an employee and then change company, employee will change as well.

AngularJS selecting multiple options

So, What I'm trying to do is fairly simple with vanilla JS, but I'm using AngularJS and I would like to know how to do it the best way within the framework. I want to update the selected options in a multiple select box. I do not want to add or remove any of the options. Here is what my HTML looks like:
<select multiple>
<option value="1">Blue</option>
<option value="2">Green</option>
<option value="3">Yellow</option>
<option value="4">Red</option>
</select>
Using the following array, I'd like to programmatically select/deselect options from this list:
[{id:1, name:"Blue"},{id:4, name:"Red"}]
When I set this array in the scope, I want the select box to deselect anything that is not Blue or Red and select Blue and Red. The standard response that I've seen on the Google Groups is to use ng-repeat. However, I can't recreate the list every time because the list of selected values is incomplete. As far as I can tell, AngularJS has no mechanism for this, and I'm at a loss as to how I would do this without resorting to using jQuery.
ngModel is pretty awesome! If you specify the indexes as a model selectedValues
<select multiple ng-model="selectedValues">
built from your list (selected) in a $watch
$scope.$watch('selected', function(nowSelected){
// reset to nothing, could use `splice` to preserve non-angular references
$scope.selectedValues = [];
if( ! nowSelected ){
// sometimes selected is null or undefined
return;
}
// here's the magic
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString() );
});
});
ngModel will automatically select them for you.
Note that this data binding is one-way (selected to UI). If you're wanting to use the <select> UI to build your list, I'd suggest refactoring the data (or using another $watch but those can be expensive).
Yes, selectedValues needs to contain strings, not numbers. (At least it did for me :)
Full example at http://jsfiddle.net/JB3Un/

Categories

Resources