Using a helper as component attribute - ember.js

I need to be able to assign a string returned by a helper to a components attribute.
Here's what I got that isn't working:
{{nav-title text=(translate user.likes name=user.profile.name)}}
It tries to find translate on the controller (I guess) and throws the following error:
Handlebars error: Could not find property 'translate' on object (generated users.user.likes controller).

Don't think you can do that. I'd say either make a new property on whatever context that nav-title is being rendered in and do the logic there, or make a new component and move the logic inside.
It's ok to use components for domain-specific stuff. For example this could be a user-likes-nav component, which knows how to translate a user's likes before rendering the template.

Related

Ember observer not working on nested property

I have created a mock application to illustrate the situation I am facing: Mock App
In this application; I have created a service with a single boolean property and a function to toggle that property (x); and two components (one to toggle the service's property; the other to observe the number of toggles and display it). The observer lies in toggle-observer. It is added directly to service's property as: myService.x. The code is not working as is; however if the comment at line 14 of toggle-observer.js is commented out; the observer starts working.
My question is that, do I need to perform a get to the whole path of a nested observer property to get it working? Is this the expected behavior? If so, can somebody explain why? My best regards.
Note: This is a mock example to illustrate the case; it is not related to anything I am designing in a real app. I am trying to avoid observers as much as possible; but I ran into this situation while trying out sth. and decided to ask it.
From ember guide service
Injected properties are lazy loaded; meaning the service will not be
instantiated until the property is explicitly called. Therefore you
need to access services in your component using the get function
otherwise you might get an undefined.
From ember guide, unconsumed computed properties do not trigger observers.
By combining the above two concepts, we can come to the below conclusion,
You haven't used myService any of the property inside toggle-observer component so it will be undefined until you explicitly call get function or use it in template.
Unless you use it x property in toggle-observer component, then it will not trigger observer. You need to consume it either in toggle-observer.hbs file or in init method.

TextField View Helper - Ember.Handlebars.helpers.view.call is not a function

I'm working on upgrading my grunt CLI based ember 1.8 app to 1.10 with HTMLbars & have made progress, but my view helpers and components don't work; such as date-input, ember-select, bing-map, product-item. So I'm starting with the date-input view helper which returns this error now - "Ember.Handlebars.helpers.view.call is not a function". This input control is rendered via {{date-input... which is associated to 'DateInputView' in views/date-input.js which extends Ember.TextField. It's also associated to helpers/date-input.js and Ember.Handlebars.makeBoundHelper(). The function inside returns Ember.Handlebars.helpers.view.call() which results in the error. I read something about how maybe my template compiler isn't the new one required or maybe a Component should be used rather than a View Helper, but it seems like there should be a simple fix for the View Helper, don't you think?
Development of this viewHelper was done by another party and the purpose of the callback making a call to viewHelper is a mystery. Regardless, the use of viewHelpers is being discouraged going forward and I've re-worked the date-input as a Component.

TypeError: 'undefined' is not an object (evaluating 'store.createRecord')

I have a 'new' action within a component (Ember.Component) that has the following code in it:
var store = this.get('store');
store.createRecord('child');
yet I'm getting the following error:
TypeError: 'undefined' is not an object (evaluating 'store.createRecord')
The only way I've been able to proceed with this is to find the parent object (always set in the component) by using:
store = this.get('parent.store');
and then proceeding with the createRecord call from above. Is this the "normal" way to proceed?
The store doesn't exist inside of a component, so either you need to pass it into the component, or you have to get it from some parent controller (or passed in controller).
Via Ember Data Transition document (https://github.com/emberjs/data/blob/master/TRANSITION.md)
In general, looking up models directly in a component is an anti-pattern, and you should prefer to pass in any model you need in the template that included the component.
The bad part about it, is you are adding a dependency to ember data in your component, which is supposed to be agnostic of the outside world.

EmberJS - A way to log undefined bindings

Is there a way to get Ember to log a warning or error if you reference a property that doesn't exist? Currently if you misspell a the name of a property bound in your handlebar template there is no warning, it just doesn't show anything, and it can be hard to find which property is incorrect.
I have LOG_BINDINGS enabled, which helps somewhat, but there is a lot of unrelated stuff to sort through.
There isn't any sort of general built-in debugging that I have found, but there is a mechanism to add your own.
Ember.Object calls a method 'unknownProperty' any time a 'get' call returns undefined. You can add a console.warn to this method to log the property. The documentation describes it as a way to make custom abstract method type handling.
http://emberjs.com/api/classes/Ember.Observable.html#method_get
Ember.Object.reopen(
unknownProperty: (property) ->
unless property is 'App' or property is 'Ember'
console.warn "Unknown property #{property} in #{#toString()}"
)
Notice the filtering of the global namespaces 'App' and 'Ember' - all calls to global properties still go through this interface, but for what we care about they are red herrings.
Unfortunately, if you try to do this by reopening Ember.Object itself, you get a bunch of junk you don't care about, because apparently this happens all the time, especially in the EventManager classes. I have gotten around this by applying it to Ember.ArrayController, Ember.ObjectController, and a Model class that all of my models inherit from.
I now get a neat warning message on the console instead of a blank page every time I accidentally type "hight" into handlebars instead of "height"
In a production solution one would want to link this to some kind of "debug" option in the build, I assume.
One half solution might be to use the log handlebars helper to log the property before using it, unfortunately a non existent property causes the template to not display at all. This is a common problem with handlebars not displaying errors.
{{log myProperty}}

ember js compare values in DOM if statement or at least in a View with value from DOM

I been trying to compare some values in handlebars if statement {{#if value == 'otherValue'}}, obviously unsuccessfully because handlebars do not like this and expecting a string, boolean, or function name. Well that would be ok, but then I tried to pass parameter in the function like you can do with {{action}} helper, and well that didn't workout either, got this in console
Error: assertion failed: You must pass exactly one argument to the if helper
So then I decided to do this in a View, even so ember js guides points that accessing template values in-scope is unusual and they provide only poor paragraph with no examples.
http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_accessing-template-variables-from-views
So when I tried to do this, I got a problem of accessing those variables, I tried this way this.get('controller.templateVariables') and via full path to View, but value was either undefined or .get() wasn't exists as a method.
So at this moment I decided to save variable in the DOM data property, but turns out this {{#view App.TabsView data-title="{{tab}}"}} is going to literately give me a string {{tab}} when I try to access it from View with this.get('data-title').
The only way left to me was to insert additional element inside view and store variable there, and afterwards access it with jQuery class selector. but element is not yet exist in the DOM at the time of isVisible function gets executed, so I have no access to values at that time. That explains why this.get('element') was returning null.
Similar examples on ember js mostly ends up with something like if (someLogic) {}, but how I can do any logic when there is no variables available to me.
Question
To simplify my question - is there a way how I can do such a thing in ember js? Simple as
// have objects stored in controller
var obj = [{title:'Tab1'}, {title:'Tab2'}, {title:'Tab3'}];
// loop via them in the DOM
obj.forEach(function(tab) {
// do this kind of comparison
if( tab.title == currentTab() ) {
// do something here
}
});
If that is not possible, then what would be the other way to achieve similar functionality?
You can write a handlerbar helper to do this
{{activeTab tab}}
Handlebars.registerHelper('activeTab', function(tab) {
})
See a question about the same issue
Active Tab
Or look at existing helpers to write your own
Bind Helper
Template Helper
I think the best way for me to demonstrate this is with a heavily commented JSFiddle that I've put together for you: http://jsfiddle.net/PbLnm/
Please ask any questions below if you're not sure about anything.
The main part which determines when to add the active class is in the computed property:
// Determine if the object we have for this view is the same as the activeTab's object. If it is the same, then this view is the current active tab.
active: function() {
return Boolean(this.get('parentView.activeTab') == this.get('tab'));
}.property('parentView.activeTab')