I have this an ArrayController with some elements in it. I display a property "content" of the elements in a list with Handlebars like this:
{{#each}}
<div id="editable" contenteditable="true">
<li>{{content}}</li>
</div>
{{/each}}
As noted in the template, I also make this editable (I have integrated the inline CKEditor) and I can edit these list items when I load the app.
The problem is that the changed data is not reflected back to the element object of the ArrayController, so that after I call save on the model, the "content" property is back to its original value.
If I modify the data by the ember textfield view, everything works fine, so changes are stored back into the element.
{{#each}}
<div id="editable" contenteditable="true">
<li>{{textarea value=content}}</li>
</div>
{{/each}}
Is there a way to tell handlebars that all element values should be two-way bound to the properties?
You need to bind value to the content.
This should solve your problem
<textarea {{bind-attr value=content}} />
// or
{{view Ember.TextArea value=content}}
The CKEditor must create a 'textarea' when you add 'contenteditable="true"'
This textarea is not bound to Ember controller.
So you can do :
1) get the value from CKeditor in the 'save' action.
or
2) Change CKeditor to make it Ember compatible.
Related
So I have two components in my Ember app, game-instance and game-card. The idea is that I will pass a 'cards' number attribute to game-instance and it will create x instances of game-card. Here's the setup
game.hbs (the main file):
<div>
{{input type="number" min="2" max="24" placeholder="enter a number from 4 to 24"
value=inputValue
key-up=handleInputChange}}
{{game-instance cards=inputValue}}
</div>
game-instance.hbs
<div>
<!-- iteratively create game cards based on cards attribute passed -->
</div>
game-card.hbs
<div class="gamecard">
<img src="" />
</div>
When trying to figure out how to write up the game-instance.hbs logic, I've seen how handlebars allows you to iterate over an array. This is not really what I want. What I want is this behaviour:
game-instance reads its cards attribute passed from game.hbs. In this case let's assume 6
a type of for-loop logic creates six instances of game-card within game-instance.
Is there an appropriate handlebars syntax to achieve this? If not, how can I achieve similar behaviour? Thanks very much.
Idea is you need to use component helper along with #each block with cards array. so that whenever we change cards array,it will re-render the whole block.
After user entering input,you can create/update cardsArray. that will automatically rerender game-card component in game-instance component
game-instance.hbs
{{#each cardsArray as |value,index|}}
{{component 'game-card' value }}
{{/each}}
Whenever we change cardsArray using pushObject or chagning the entire reference then then each block will be rendered.
I have a few input fields being displayed programatically via the Ember each helper. These inputs are related to data being returned from my database, and I have a corresponding unique ID for each input that I could use if necessary.
My question is how can I store the value of these dynamically generated inputs on my controller so that I can access the user's input data? I was trying to do something like this:
{{#each solutionTypes as |solutionType|}}
{{input value=inputData[solutionType.id]}}
{{/each}}
However, trying to access an object or array in this manner causes a build error related to the the above syntax in specifying the value (object dot notation causes a build error too).
In short, I am trying to save the value of the input field as a property on an object or in an array instead of as a plain variable on the controller. I would like the input data from all of the inputs in the form to be accessible from the "inputData" variable in the following form:
{
"1000": "data from first input",
"1001": "data from second input",
"1002": "data from third input"
}
The primary issue is utilizing the dynamic keys (from solutionType.id) in the handlebars code without getting a build error.
If this is not possible using the value attribute but you know how to accomplish this with actions or with something else, I'm more than open to your ideas.
The question is a tad confusing so I'll answer in both ways I interpreted your question.
Two-way binding
The {{input}} helper establishes a two way binding with the value so in your example:
{{input value=solutionType.value}}
will bind the solutionType.value to the input. Not only will it display that value but it means as the user types into the input it will update solutionType.value.
One-way bindings (Data Down Actions Up)
Based on your use of inputData being different then solutionType I assume you want a one way binding.
The community standard is to use Data Down Actions Up in such that the solutionType.value does not change as the user enters data but instead sends an action back up so you can manage it as you see fit.
Unfortunately the current Ember {{input}} helper does not support this. There is an addon called ember-one-way-controls which will do this for you. You might want to experiment with that.
A caveat with the above addon is that you will have to manage the solutionTypes data manually as the actions come back up.
Ultimately you will have to decide just how tightly coupled the data you display via an input field is to the data you expect the user to type and adjust your design accordingly.
Yes. You can utilize the dynamic keys (from solutionType.id) in the handlebars code without getting a build error by using get and mut helper it's possible. ember-twiddle
For two way binding,
{{input value=(mut (get inputData (get solutionType 'id'))) }}
For one way binding,
{{input value=(get inputData (get solutionType 'id')) }}
routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model(){
return [{id:'1000'},{id:'1001'},{id:'1002'}];
},
setupController(controller,model){
this._super(...arguments);
controller.set('solutionTypes',model);
}
});
controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
inputData:{'1000': "data from first input", '1001': "data from second input",'1002': "data from third input"},
});
templates/application.hbs
<h1>Welcome to {{appName}}</h1>
<br>
<h1> One way binding </h1>
{{#each solutionTypes as |solutionType|}}
{{input value=(get inputData (get solutionType 'id')) }}
{{/each}}
<h2> Two way binding </h2>
{{#each solutionTypes as |solutionType|}}
{{input value=(mut (get inputData (get solutionType 'id'))) }}
{{/each}}
<br>
<h2> Result </h2>
{{#each solutionTypes as |solutionType|}}
<span> {{get inputData (get solutionType 'id')}} </span>
{{/each}}
<br />
{{outlet}}
<br>
<br>
what i basically done is sorted my content according to some properties and used arrangedContent so that i can get the sortedcontent. Now i want to filter my model using some keys in model(eg:name) and want only that content to display in template.what i want is when i type some name in the search field text box,the content should be filtered and controller will only have to display the filtered content with my sorting properties applied.
{{#each arrangedContent}}......{{/each}}
{{input type="text" action="search" valueBinding="criteria" placeholder="Search"}}
when i enter the name,the model should be filtered and arrangedContent should only display that filtered content
I am a beginner in ember and cant find a way to do the above thing.
I implemented a similar case. Keeping use of the arrangedContent.
filteredContent: function(){
var content = this.get('arrangedContent');
// perform criteria on content
// e.g.: content.findBy('name', criteria)
return content;
}.property('arrangedContent.#each', 'criteria')
Your handlebars template:
{{#each filteredContent}}......{{/each}}
{{input type="text" action="search" valueBinding="criteria" placeholder="Search"}}
You will keep the advantages off arrangedContent, whilst still being able to modify it.
I'm trying to link a label to an input field using the {{bindAttr}} and the input field's [viewName].elementId. It works on a single entry view, but not when there are several records being displayed: it just links the label to the last input field in the collection. (This used to work in a previous iteration using an older ember library but now it doesnt.) I've created a fiddle but the gist of it is:
{{#each controller}}
<fieldset>
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</fieldset>
{{/each}}
I thought maybe I could create a collectionView and create a calculated property for viewName which would generate a unique ID for each item in the collection, sort of mentioned in answer to another problem here. But that is getting WAY too complicated - just so that I can have the input field highlight itself if the user clicks on the corresponding label.
Any help appreciated.
Create a wrapper Ember.View around the label and input field. Let's call it App.FieldView:
App.FieldView = Ember.View.extend({
tagName: 'fieldset'
});
Then in your template:
{{#each controller}}
{{#view App.FieldView}}
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
{{/view}}
{{/each}}
Fiddle: http://jsfiddle.net/NQKvy/26/
Panagiotis Panagi, has answered the question correctly. I'll just add why this is happening, ie:- linking to the incorrect view.
The view property inside a template refers to the Ember View wrapping the html markup. This property however has different value depending on the context it is in.
This value is dependent on the view block it placed in. By default the template itself corresponds to a view in this case, ListOfPeopleTemplateView.
So when you are binding to view.tbFullName.elementId, you are actually binding to an {instance of ListOfPeopleTemplateView}.tbFullName.elementId. And when the loop finishes the only tbFullName visible is the last one.
Panagiotis Panagi's solution is to wrap the label inside another view, so the value of view changes to within that block, and hence points to the correct tbFullName
Finally an even easier way to achieve the same result is to wrap the textfield inside the label. Then you do not need the label for binding at all.
<label>Full Name
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</label>
See this jsfiddle
Forms are somewhat tricky I must admit if you want to do things right. But there are is an ember add-on that comes to the rescue, for example easyForm.
Have a look it might helps you solving exact the problems you are facing, like the ones on having unique labels for your form fields etc.
Hope it helps.
I have the following template setup displaying a list of items, and wrapping each list in its own controller:
{{#each controller itemController="contact"}}
<div class="contact-entry">
<div class="title" {{action toggle on="click"}}>{{title}}</div>
{{#if showDetails}}
<div class="details">
<div>{{safe details}}</div>
</div>
{{/if}}
</div>
{{/each}}
The main controller is an ArrayController called ContentsController, and each item is wrapped in an ObjectController called ContentController. The content of the ContentsController is set explicitly in the route (I've simplified the data):
App.ContactsRoute = Em.Route.extend({
model: function() {
return [{'title': 'first'}, {'title': 'second'}];
}
});
This works really well. However if I navigate to another path and then back again, the settings on the ContentController don't persist. What happens is that the model data gets reloaded, and I assume a ObjectController gets created for each of the list items. Incidentally this is not the case for the ContentsController, which keeps its settings.
What is the solution to preventing ember of creating new ContentController for every list item every time I access the page?
I'm assuming your reference to ContentController is really ContactsController since you are using itemController="contact" in your #each block.
What kind of data are you trying to persist? The showDetails flag? The ContactControllers are going be created and destroyed anytime you exit / enter the route and there isn't anyway I know of to keep those around.
The ContactsController keeps its properties because its a singleton controller generated because you have a ContactsRoute.