Ember computed property on a controller not bound in template - ember.js

I'm trying to implement a password strength checker that will update on every key press. My template looks like this:
{{input type="password" id="password" value=password }}
My controller looks like this:
App.SignupController = Ember.Controller.extend
passwordStrength: ((key,val) ->
# check strength if val is defined
return
).property('password')
passwordStrength is never called when text is entered in the field.
However, if I rename the method to just password and remove the computed property's name, it does work:
App.SignupController = Ember.Controller.extend
password: ((key,val) ->
# check strength if val is defined
return
).property()
I'd rather understand why the former was not working though, and use a more sensibly named method too.

I've created a jsbin for you to look at that is working and updating when the password is updated. I think I know why this is not working for you. in my js bin here http://emberjs.jsbin.com/gekofo/4/edit?html,js,console,output You will notice that only the observer console.logs. Whereas in your program I would imagine you maybe aren't displaying the passwordStrength value. If you add {{passwordStrength}} into the template in my bin, you will see that the property gets updated. So it looks like you may want to use the passwordStrength2 that i have written, because it will update whether it is displayed in the DOM or not.
In short use this:
passwordStrength2: function() {
//check strength if val is defined
console.log("OBSERVER::", this.get('password.length'))
return this.get('password.length');
}.observes('password')
NOT:
passwordStrength: function() {
//check strength if val is defined
console.log("PROPERTY::", this.get('password.length'))
return this.get('password.length');
}.property('password')
Also I do not know coffeescript, so sorry my answer is in javascript.

Related

Ember acceptance test for chosen-select

Chosen is working great for me but I cannot figure out how to get my acceptance test to send in the value on the form submit.
Handlebars template:
<form>
{{#ember-chosen value=country}}
{{#each countries as |country|}}
<option value={{country}}>{{country}}</option>
{{/each}}
{{/ember-chosen}}
{{#link-to 'countries.show' (query-params country=country) tagName='button' type='submit' replace=true class="submit__button"}}Search{{/link-to}}
</form>
Acceptance test:
test 'Searching for a country', (assert) ->
visit '/search'
find('.chosen-select').val('USA')
find('.chosen-select').trigger('chosen:updated')
click('.submit__button')
andThen ->
assert.equal find(".chosen-select :selected").text(), "USA"
This fails because on submit country is not even passed in as a query param, but only in the test.
The same thing happens if I do it in the console. If I open my console and do:
$('.chosen-select').val('USA')
$('.chosen-select').trigger('chosen:updated')
then the selection updates before my eyes! But then clicking submit produces the same results as the test, that is, the country is not passed into the query-params.
Clicking "USA" from the dropdown however, then clicking submit, works perfectly.
UPDATE
Chad Carbert's response below gave me the answer. Here are the specific results:
$('.chosen-select').val('USA')
$('.chosen-select').trigger('chosen:updated')
updates the DOM only. Not the data-bindings with Ember.
$('.chosen-select').trigger('change', {'selected': 'USA'})
updates the data-bindings (which is what I really need), not the DOM.
Since this is for my acceptance tests only and I don't need to see the DOM change, my test now looks like this:
test 'Searching for a country', (assert) ->
visit '/search'
find('.chosen-select').trigger('change', {'selected': 'USA'})
click('.submit__button')
andThen ->
assert.equal find(".chosen-select :selected").text(), "USA"
Which works like a charm! If you wanted to though, there would be no harm in doing all three:
test 'Searching for a country', (assert) ->
visit '/search'
find('.chosen-select').val('USA')
find('.chosen-select').trigger('chosen:updated')
find('.chosen-select').trigger('change', {'selected': 'USA'})
click('.submit__button')
andThen ->
assert.equal find(".chosen-select :selected").text(), "USA"
Thank you Chad!
It looks like this might be an issue with the way that this component wraps the jQuery library. Looking at the documentation for chosen:
Updating Chosen Dynamically
If you need to update the options in your select field and want Chosen to pick up the changes, you'll need to trigger the "chosen:updated" event on the field. Chosen will re-build itself based on the updated content.
via chosen docs
However, it doesn't look like the ember component is wrapping that event in any way. It also looks like the chosen:update is updating the chosen UI implementation, but not the data binding within Ember. This would be in a case where you've after the fact added options to the select, and want these reflected ('rebuilt') on the screen.
Looking at the code behind this component and how it's wrapping the chosen library, it appears that this component is only capturing the change event. So try doing a trigger on a change event and that should have things update within ember, and its data binding.
Or try triggering the change the way it's mentioned on the Chosen docs:
Form Field Change**
When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event* on the original form field. That let's you do something like this:
$("#form_field").chosen().change( … );
If that doesn't work, if you're able to provide a codepen I will take a look closer, thanks!

Simple search with Emberjs not working

I am trying to implement a simple search feature, which will filter the results and update the listing.
I tried almost every single tutorial out there, every tutorial seems to be working with its jsfiddle but when I apply the same thing on my project, it does not work at all.
Here is what I am having as a first problem, my search field does not seems to be bound with computed property in controller.
I also tried it as a component but again same issue, if I type anything in search field it does not reflect anything.
Let me share my code here,
input type="text" value=searchText placeholder="Search..."
searchResults: ( ->
console.log "On every key press it should come here.."
model = #get('model')
searchText = #get('searchText')
filterByPath = #get('filterByPath')
visualPath = #get('visualPath')
if searchText
searchText = searchText.toLowerCase()
model = model.filter(item) ->
Ember.get(item, filterByPath).toLowerCase().indexOf(searchText)>= 0
model.getEach(visualPath)
).property('searchText')
Tried almost the same thing with component, but no luck so far. I am not using handlebars but Emblemjs.
You actually need to use computed property in template if you want it to be compiled, then recompiled etc. It is somewhat lazily evaluated so you can't debug that without using this in template first or calling from JavaScript code. So basically you need to use searchResults in your template first.
In demo there was model instead of searchResults. I guess in your application you have similiar setup and same bug.
Fix:
{{#each searchResults as |item|}}
<li>{{item}}</li>
{{/each}}
Working demo.

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')
});

Ember/Handlebars: compare variable with string

I need to display some block depending on the current views variable in comparison to some string:
PSEUDO code is:
{{#if view.someVariable "desiredValue"}}
Hurray desiredValue exists in this view!
{{else}}
Sorry, doesn't match...
{{/if}}
Of course it doesn't work as if statement allows only one param. I tried with custom registerHelper of Handlebars, but it doesn't resolve the view.someVariable, instead uses it as a string (although view.someVariable is defined and has value).
Finally I also tried with Handlebar's registerBoundHelper - it resolves the params BUT doesn't support Handlebar's blocks, what's more tries to resolve the string as an object, so fail again. Pure madness!
My views are very dynamical they depends on many factors also from backend and approach from the pseudo code would be perfect for resolving it. Is there any way to do that?
Edit:
There is a sample of what I want ... http://jsfiddle.net/biesior/dMS2d/ looks quite trivial...
[if] statement inside the each is pseudo code of course
You can just declare a computed property, something like isDesired on your view, which would compare someVariable to your string:
App.MyView = Ember.View.extend({
// ...stuff...
isDesired: Ember.computed.equal('someVariable', 'desiredValue')
});
And have a simple conditional in the template:
{{#if view.isDesired}}
Hurray desiredValue exists in this view!
{{else}}
Sorry, doesn't match...
{{/if}}

Ember Data: Proper Way to Use findAll

I am trying to use ember-data using https://github.com/emberjs/data as a reference.
Specifically, I am trying to use an array controller to display all of the 'Person' objects in my database. I also want to allow the user to create a new 'Person'.
I have the following code which works:
App.peopleController = Em.ArrayController.create
content: App.store.findAll(App.Person)
newPerson: (name) ->
App.store.create App.Person,
name: name
#set('content', App.store.findAll(App.Annotation))
However, it seems inefficient to reset the content property every time a new person is created. If I remove the last line and change the code to the following:
App.peopleController = Em.ArrayController.create
content: App.store.findAll(App.Person)
newPerson: (name) ->
App.store.create App.Person,
name: name
A new view is still created on ever newPerson call, but the same object is duplicated. Essentially what is happening is all of the new templates use the first object created instead of a new one each time. I think this is related to the following bug: https://github.com/emberjs/data/issues/11.
For reference, my template logic is as follows:
{{#each App.peopleController}}
{{#view App.PersonView contentBinding="this"}}
{{#with content}}
Client id is {{clientId}}
{{/with}}
{{/view}}
{{/each}}
When I use the second version of my code-- the one with the #set('content', App.store.findAll(App.Annotation)) line-- the clientId is duplicated for every Person object. In the first version, the client ids are correct.
Can anyone shed some light here? Am I doing this correctly? My instincts are telling me this is a bug but I am not sure.
I think it is a bug. I posted a related issue that illustrates this issue.
Try using the #collection view instead.
See code of ToDo example. Also see http://guides.sproutcore20.com/using_handlebars.html section 5 for some documentation.
Hope this helps.