How to generate a number of ember-power-select using each loop? - ember.js

I am suing code below to generate a list of ember-power-select component.
{{#each query_params as |param|}}
<div>
<label for="">{{param.param}}</label>
{{#power-select
options=param.options
selected=option
onchange=(action (mut selectedName))
allowClear=true
class="bar-query--inputs-auto"
as |name|
}}
{{name}}
{{/power-select}}
</div>
{{/each}}
However, selected=option makes all the generated power-select component share the same selected property option. The effect is whenever anyone select's value changes all others selects value will get updated as well.
How should I solve this issue?

{{#each query_params as |param|}}
<div>
<label for="">{{param.param}}</label>
{{#power-select
options=param.options
selected=param.selected
onchange=(action (mut param.selected))
allowClear=true
class="bar-query--inputs-auto"
as |name|
}}
{{name}}
{{/power-select}}
</div>
{{/each}}
I solved issue by changing select=option to select=param.selected.

Related

ember-power-select cannot type in it

I'm wondering if this is really an issue with ember-power-select, but I cannot type in it. The dropdown can be opened, but there is no display.
This is a template in which I call my component:
<div class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu">
<li>
{{global-search label=(t 'search')}}
</li>
</ul>
</div>
</div>
And the template of my component:
{{#bs-form as |form|}}
{{#form.element label=(t 'search')}}
{{log allObjects}}
{{#power-select
selected=selected
options=allObjects
placeholder='test'
onchange=(action (mut selected))
as |name|
}}
{{name}}
{{/power-select}}
{{/form.element}}
{{/bs-form}}
And finally my components:
import Ember from 'ember';
export default Ember.Component.extend({
allObjects: ['test', 'foo']
});
The answer is very simple. My power-select was hidden behind my other <li>. I just had to add this in my template in my power-select:
renderInPlace=true

How to use ember-power-select in {{#each}} block

I am generating ember-power-select box using {{#each}} block in hbs template as shown in the code below.
{{#each hps as |hp|}}
{{#power-select
search=(action "searchRepo")
selected=selected
onchange=(action (mut selected))
as |repo|
}}
{{repo.name}}
{{/power-select}}
{{/each}}
The above code generates two select boxes. But when I select a value in the first box,the same value gets replicated in the second box too.
What is the way to differentiate the two select boxes?
This works for me
// Controller
roles: ['Project Manager', 'Tech Lead', 'Member'],
<ul>
{{#each user.projectRoles as |projectRole|}}
<li>
<label>{{projectRole.project}}</label>
{{#power-select selected=projectRole.role options=roles onchange=(action (mut projectRole.role)) as |role|}}
{{role}}
{{/power-select}}
</li>
{{/each}}
</ul>
The only thing I can think of that may work is declaring selected as an array and bind every power select selected property to the correspondent index of the hp array.
For example, assuming you're using a component:
import Ember from 'ember';
export default Ember.Component.extend({
selected: Ember.A()
});
Then, in your component template:
{{#each hps as |hp hp_index|}}
{{#power-select
search=(action "searchRepo")
selected=selected.[hp_index]
onchange=(action (mut selected))
as |repo|
}}
{{repo.name}}
{{/power-select}}
{{/each}}
This is mainly happening of because you are assigning same as |repo| in both of the select statements so whenever you change one it is reflecting in the both.
{{#power-select}}do not have option like this better you try with some other one
or
else you define two {{#power-select}} with different as |repo2|

How to set itemController for instance variable in ember.js indexController?

I have a Ember.js page that displays a table of items and shows details of one of the items when it is selected. The controller looks like this:
CV.IndexController = Ember.ArrayController.extend({
itemController: "CurrVitae",
selectedCurrVitae: false,
actions: {
selectCurrVitae: function(currVitae) {
this.set('selectedCurrVitae', currVitae)
}
}
});
And the index controller is used in a template like this:
<div class="container">
<div class="curr-vitae-list">
{{#each curr_vitae in controller}}
<div class="curr-vitae-item row">
<div class="col-sm-2" {{action selectCurrVitae curr_vitae}}>
{{curr_vitae.name}}
</div>
<div class="col-sm-2">
<!-- NOTE: This method is defined on the item
controller (not the model) so the itemController is
available at this point. -->
{{curr_vitae.createdAtDisplay}}
</div>
<div class="col-sm-7">
<div class="embedded-cell">
{{curr_vitae.summary}}
</div>
<div class="embedded-cell">
{{curr_vitae.objective}}
</div>
</div>
</div>
{{/each}}
</div>
<div class="curr-vitae-view">
<h2>Details</h2>
<!-- EDIT: I have tried setting this
as {{#if selectedCurrVitae itemController="currVitae" }}
to match the way the #each handles item controllers but that did
not seem to work -->
{{#if selectedCurrVitae }}
<!-- NOTE: Down here, however, the item controller is not available
so I can't use methods defined on the item controller for the
currently selected instance. -->
{{ partial "cv_index_details" }}
{{/if}}
</div>
</div>
Question: The problem I'm running in to is that the itemController I've set in the index controller is not available when rendering the selectedCurrVitae in the cv_index_details.
More details:
Specifically, in the partial I want to reuse a editor component (taken from Noel Rappin's Ember.js book). So if the cv_index_details partial looks like this:
<h3 class="selected_cv">{{selectedCurrVitae.name}}</h3>
<div class="row selected_cv_summary">
<h4>Summary</h4>
{{block-editor emberObject=selectedCurrVitae propName="summary" action="itemChanged"}}
</div>
<div class="row selected_cv_experiences">
<h4>Experiences</h4>
{{#each experience in selectedCurrVitae.experiences itemController="experience"}}
{{ partial "experience_detail" }}
{{/each}}
</div>
So in this template, the itemChanged action is not found for the selectedCurrVitae instance. However, I use the same block-editor component for the experience instance and that works correctly; the itemChanged action defined on the ExperienceController is found.
selectedCurrVitae is outside of the itemController, the itemController is only applied inside the each (on each item, hence the name).
Probably the easiest way to accomplish this will be to reuse the item controller and use render.
Template
{{#if selectedCurrVitae }}
{{ render "cv_index_details" }}
{{/if}}
Controller
CV.CvIndexDetailsController = CV.CurrVitaeController.extend();
Or
Template
{{#if selectedCurrVitae }}
{{ render "currVitae" }}
{{/if}}
View
CV.CurrVitaeView = Ember.View.extend({
templateName: 'cv_index_details'
});

Extending Em.TextField

I need to make a bootstrap form with 10 textfield elements.
From the bootstrap doc, I need to have this code for each textfield element:
<div class="control-group">
<label class="control-label" for="inputEmail">Email</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Email">
</div>
</div>
Em.TextField object only manage the
<input type="text...
and I would like to minimize my handlebar form.
What is the best solution to have the expected result with the minimum of code ?
Is there a sample code for this ?
You can create a new view that includes all of the required bootstrap markup and incorporates the built in Ember.TextField input element. The custom TextField has an added label property that sets the text for the form label.
JSBin Example
Custom TextField:
JS:
App.BootstrapTextFieldView = Ember.View.extend({
templateName: 'bootstrapTextField',
inputElement: null
});
Handlebars:
<script type="text/x-handlebars" data-template-name='bootstrapTextField'>
<div class='control-group'>
<label class="control-label" {{bindAttr for='view.inputElement.elementId'}}>{{view.label}}</label>
<div class="controls">
{{view Ember.TextField valueBinding='view.value' viewName="inputElement"}}
</div>
</div>
</script>
Using the new view
You would use it similar to using the normal Ember.TextField:
<form class="form-horizontal">
{{view App.BootstrapTextFieldView valueBinding='textFieldValue' labelBinding='textFieldLabel'}}
</form>
The only tricky part was correctly setting the for='..." property on the <label> since we need to get the auto-generated id of the {{view Ember.TextField ...}}. This can be done by using the viewName property of the {{view ...}} helper. Setting {{view App.theViewHere viewName='desiredViewName' lets us access the instance of Ember.TextField we created and set the for property of the label to the view's id using the {{bindAttr...}} helper.

bindAttr reverse boolean

In my view I have a button which I want to be disabled when the data of the model is not dirty.
When I output: <button {{ action "update" }} {{bindAttr disabled="isDirty"}}>Save</button> it is enabled when the data is not dirty, and disabled when the data is dirty.
I want to reverse that so I tried this: <button {{ action "update" }} {{bindAttr disabled="!isDirty"}}>Save</button> but now is doesn't check the dirtyness at all. How do I reverse the boolean within a bindAttr helper?
Here is my code:
Controller
App.SiteController = Em.ObjectController.extend({
isNotDirty: function() {
return !this.get('isDirty');
}.property('content')
});
App.SiteEditController = Em.ObjectController.extend({
needs : [ 'site' ]
});
Template
{{#with controllers.site}}
<div>{{ isDirty }}</div>
<div>{{ isNotDirty }}</div>
<div class="control-group">
<label class="control-label" for="name">Name</label>
<div class="controls">
{{view Ember.TextField valueBinding="name"}}
</div>
</div>
<div class="form-actions">
<button {{bindAttr disabled="isNotDirty"}} class="btn btn-primary">Save</button>
</div>
{{/with}}
I outputted the isDirty an isNotDirty property so I could watch them change. But only the isDirty property changes when I change the value of the text-field,
The solution can be found in the API-docs of Ember. There is a list of all available shorthand computed helpers.
I used Ember.computed.not for this case:
App.SiteController = Em.ObjectController.extend({
isNotDirty: Ember.computed.not('isDirty')
});