Emberjs Textarea 2 way binding with data that needs to be a getter - ember.js

I am using Emberjs Textarea which has 2 way binding with the #value attribute.
The data I am passing into the value is from an argument and therefore needs to be return from a getter before I can use it in the template.
My question is how do I use 2 way binding with a getter. I keep on getting error messages stating that Cannot set property inputText of #<InputComponent> which has only a getter
I have tried to use {{mut}} and tried to create a setter for the getter but nothing has worked.
The post requests actually work but I still get those annoying errors in the console.
// Component JS
get inputText() {
return this.args.text;
}
// Component Template
<Textarea #value={{this.inputText}} #focusOut={{this.postRequest}} />

Looks like setting the args value directly in the template will work.
<Textarea #value={{#inputText}} #focusOut={{this.postRequest}} />

Related

Ember helper has undefined values

I can't figure out why the helper I created in app/helpers/shop-name.js:
import { helper } from '#ember/component/helper';
export function shopName(shop) {
return shop.identifier + '-' + shop.name;
}
export default helper(shopName);
doe not format the values as needed in my template application.hbs:
<select>
{{#each model as |shop|}}
<option value={{shop.id}}>{{shop-name shop}}</option>
{{/each}}
</select>
I get undefined-undefined displayed in my select list.
If I do the same conversion directly in the template:
<option value={{shop.id}}>{{shop.identifier}}-{{shop.name}}</option>
it works as needed. What's wrong with that helper ?
I'm using Ember 3.0.
Thank you.
I'm not sure that helpers can take inputs that aren't strings. I hope someone can confirm.
Anyway, your use case is really better handled at the model level, using a computed property:
shopName: computed('identifier', 'name', function() {
return `${identifier} - ${name}`;
})
and then you would just use {{shop.shopName}} in your template
There are multiple issues in your code.
shop is an object and I bet it's an Ember.Object. If dealing with Ember.Objects, you should always use get() method to retrieve values for now. This might change soon. Since you are not using get() method, you get undefined. Embers template engine is using getter and therefore it's a huge difference between shop.identifier in your helper and {{shop.identifier}} in your template. Resolve the issue by shop.get('identifier') or import { get } from '#ember/object'; [...] get(shop, 'identifier'); Use the last one if you can't be sure that shop is an instance of Ember.Object.
Since you are passing shop and not shop.identifier as argument to your helper, the helper will only be recomputed if the reference of shop changes (e.g. replaced by another object). Changes to the value of it's properties will not recompute the helper.
One solution for you problem is to use a computed property as suggested by ctcpip. Another one is the concat helper: {{concat shop.identifier '-' shop.name}}.

CFWheels: Display form errors on redirectto instead of renderpage

I have a form which I am validating using CFWheels model validation and form helpers.
My code for index() Action/View in controller:
public function index()
{
title = "Home";
forms = model("forms");
allforms = model("forms").findAll(order="id ASC");
}
#startFormTag(controller="form", action="init_form")#
<select class="form-control">
<option value="">Please select Form</option>
<cfloop query="allforms">
<option value="#allforms.id#">#allforms.name#</option>
</cfloop>
</select>
<input type="text" name="forms[name]" value="#forms.name#">
#errorMessageOn(objectName="forms", property="name")#
<button type="submit">Submit</button>
#endFormTag()#
This form is submitted to init_form() action and the code is :
public function init_form()
{
title = "Home";
forms = get_forms(params.forms);
if(isPost())
{
if(forms.hasErrors())
{
// don't want to retype allforms here ! but index page needs it
allforms = model(tables.forms).findAll(order="id ASC");
renderPage(action="index");
//redirectTo(action="index");
}
}
}
As you can see from the above code I am validating the value of form field and if any errors it is send to the original index page. My problem is that since I am rendering page, I also have to retype the other variables that page need such as "allforms" in this case for the drop down.
Is there a way not to type such variables? And if instead of renderPage() I use redirectTo(), then the errors don't show? Why is that?
Just to be clear, I want to send/redirect the page to original form and display error messages but I don't want to type other variables that are required to render that page? Is there are way.
Please let me know if you need more clarification.
This may seem a little off topic, but my guess is that this is an issue with the form being rendered using one controller (new) and processed using another (create) or in the case of updating, render using edit handle form using update.
I would argue, IMHO, etc... that the way that cfWheels routes are done leaves some room for improvement. You see in many of the various framework's routing components you can designate a different controller function for POST than your would use for GET. With cfWheels, all calls are handled based on the url, so a GET and a POST would be handled by the same controller if you use the same url (like when a form action is left blank).
This is the interaction as cfwheels does it:
While it is possible to change the way it does it, the documentation and tutorials you'll find seem to prefer this way of doing it.
TL; DR;
The workaround that is available, is to have the form be render (GET:new,edit) and processing (POST:create,update) handled by the same controller function (route). Within the function...
check if the user submitted using POST
if it is POST, run a private function (i.e. handle_create()) that handles the form
within the handle_create() function you can set up all your error checking and create the errors
if the function has no errors, create (or update) the model and optionally redirect to a success page
otherwise return an object/array of errors
make the result error object/array available to view
handle the form creation
In the view, if the errors are present, show them in the form or up top somewhere. Make sure that the form action either points to self or is empty. Giving the submit button a name and value can also help in determining whether a form was submitted.
This "pattern" works pretty well without sessions.
Otherwise you can use the Flash, as that is what it was created for, but you do need to have Sessions working. their use is described here: http://docs.cfwheels.org/docs/using-the-flash and here:http://docs.cfwheels.org/v1.4/docs/flashmessages
but it really is as easy as adding this to your controller
flashInsert(error="This is an error message.");
and this to your view
<cfif flashKeyExists("error")>
<p class="errorMessage">
#flash("error")#
</p>
</cfif>

How can I determine if a component returns nothing dynamically?

I have a ember component that is accessing a database and returning the results in a datatable type UI component. I would like to be able to use "N/A" when the result of the component is null or nothing.
For example, I have:
{{each bar in foobars}}
<td class="classyTD">
{{getBars bar=bar}}
</td>
{{/each}}
This works great when I have data, but returns nothing when I don't have data. The designers would prefer an "N/A". Modifying the database isn't an option and while modifying the component getBars is an option, it will be extremely painful.
Is there a method/way to handle this after the execution of the component? If not, or if it's a terrible idea - I'll suffer through changing the component, I trust the community's opinion.
You really should do this inside the component template. You can give the N/A string as a parameter, if that's of any help: http://emberjs.jsbin.com/lemabekuwi/2/edit?html,css,js,output
Or you could change the component that it indicates emptiness through a class and use some css magic: http://emberjs.jsbin.com/duqazahegi/1/edit?html,css,js,output
If you want to limit logic in the handlebars you can have the following in the component js file:
({
setBar: (function() {
if (!this.get('bar')) {
return this.set('bar', 'N/A');
}
}).observes('bar')
});

How to render a component based on model parameter

I have the requirement to render a template based on a property of my model.
My stratergy was to use custom if block helpers for the handle bars templates, something like this:
{{#ifequals type 'cars'}}
{{cars-component}}
{{/ifequals}}
{{#ifequals type 'planes'}}
{{planes-component}}
{{/ifequals}
but I cant create a block helper that resolves parameter passed by the template to the helper.
if I use Handlebars.registerHandlebars, it resolves the variable name insted of the variable.
the reason i need to do this is because it is part of a plugin framework.
Option blocks (special if statements) don't work properly in ember handlebars helpers. https://github.com/emberjs/ember.js/issues/2237
isCar: Ember.computed.equals('type', 'cars')
isPlane: Ember.computed.equals('type', 'planes')
{{#if isCar}}
{{cars-component}}
{{/if}}
{{#if isPlan}}
{{planes-component}}
{{/if}}
It almost looks like you can do it, but there is a problem with it, as is pointed out in the github issue above.
Ember.Handlebars.helper('iff', function(value,property, options) {
if(value === property){
return options.fn.apply();
} else {
return options.inverse.apply();
}
});
http://emberjs.jsbin.com/UhOWeWiJ/1/edit
http://emberjs.jsbin.com/UhOWeWiJ/2/edit
You will get a bound blocks error when you try and implement something like this and the values actually change
https://github.com/emberjs/ember.js/issues/2237
Uncaught You can't use appendChild outside of the rendering process
http://emberjs.jsbin.com/UhOWeWiJ/3/edit
http://emberjs.jsbin.com/UhOWeWiJ/3/edit

Ember Handlebars Embed ID

I am trying to use ember to show a dynamic list of found content. The problem is that when I try to put handlebars in html attributes, everything breaks.
RegApp.PatronsFound = Ember.CollectionView.create
tagName: 'table'
content: []
itemViewClass: Ember.View.extend
template: Ember.Handlebars.compile("<td><button onclick='alert({{content.id}})'>{{content.name}}</button>")
RegApp.PatronsFound.appendTo('body')
When it is fed a piece of content with the ID of 3 and the name FOO, I want this html to be generated:
<button onclick="alert(3)">FOO</button>
Instead, I get this:
<button onclick="alert(<script id=" metamorph-4-start'="" type="text/x-placeholder">3<script id="metamorph-4-end" type="text/x-placeholder"></script>)'>FOO</button>
You can use
{{unbound content.id}}
to arbitrarily insert values into your templates. Normally, such values are wrapped in metamorph tags which allow the displayed value to be bound to the backing value, and updated whenever the backing value changes. This only works if the output is regular HTML, not, in this case, spanning event handlers and embedded JS. {{unbound}} inserts the value at that property path once, without metamorph tags, and without being updated if that value changes in the future.