I just started working on an existing Ember.js project that uses ember-i18n.js for localization.
Ember.Mixin.create({
setupController: function (controller, model) {
controller.set("somePropertyName", "my.translation.key");
}
});
I defined another helper that lets me get a translation key from a context property, instead of passing it in directly, e.g. I can use {{tr someContext.someProperty}} instead of {{t "my.translation.key"}}.
Ember.Handlebars.registerBoundHelper('tr', function(property, options) {
return Ember.I18n.t(property);
});
I'm fairly new to Ember, so my thought process was that I would simply be able to swap out replace {{somePropertyName}} in my template with {{tr somePropertyName}}. That didn't work. When I set a breakpoint inside the helper, I see that property is always undefined.
I also tried modifying my helper to use Ember.Handlebars.get() as demonstrated here, but that also is resolved undefined.
Assuming I'm not able to change where the translation key is coming from, is there a proper way to get the translation key from the controller to the helper?
What you are doing should be fine - the property argument to the helper is just a string, and passing a string from a controller to a template (and then to a helper) is straightforward.
So, I'm guessing (and it's just a guess without a jsbin) that either you have a coding issue somewhere. Or something weird is going on with your use of the mixin, perhaps.
I'd see how far the string property is getting from your mixin to the controller to the template to the helper.
If you change {{tr property}} does the string get written out into your template ok? If not, then the property isn't being set on your controller.
If you have a jsbin, then that would make it easier to see what is going on.
Related
I am new in AngularJS. I am learning AngularJS. In this regard I found below syntax in a tutorial.
app.config(['$routeProvider',function($routeProvider){}]);
Here .config() is a method. I am passing an array as parameter of this .config() method. '$routeProvider' and a anonymous function are two elements of that array. Am I right ??
Can I make any change of the first element of the array, like '$routeProvid' or '$routeProvideraa' or '$outeProvider'??
Can I make any change of the second element of the array, like function($routeProv) or function($routeProviraa) or function($outeProvi)??
Thanks
UPDATE
I think I failed to express. I am updating the question
Can I use below syntax??
app.config(['$routeProvid',function($routeProvider){}]);
or
app.config(['$routeProvider',function($routeProv){}]);
or
app.config(['$teProvider',function($routeProvi){}]);
Did you get this portion ??
.config() is a method. I am passing an array as parameter to this .config() method. '$routeProvider' and a anonymous function are two elements of that array.
AngularJS uses the parameter name for dependency injection; once minified the variant without the array would break.
Since strings aren't modified during minification they are used to map to their parameters. So to answer your question if you use the inline array annotation you can change the arguments to whatever you want. If you don't rename the strings or change the order of the dependencies you should be fine.
this is the annotation in AngularJS...
Basically, AngularJS provides a very useful Dependency Injection system that allows to retrieve dependencies simply declaring them as function parameters...
So, if you register something through the angular recipes, then, you are able to retrieve them in this way:
angular
.module('test', [])
.value('myValue', 'Hello World')
;
angular
.module('test')
.run(function(myValue) {
console.log(myValue);
})
;
This is very useful because allows scalability, testability, ecc... but creates one problem: It cannot be minified
The $injector cannot understand the result of the minification, because function parameters are mangled and the above code becomes:
angular.module('test').run(function(a) {console.log(a);})
So, the only way to minify angularjs code is to annotate each dependency that must be injected.
Annotation can be made in two ways:
via $inject property
using the array-like annotation
Your code belong to the second case, basically, instead of passing the function directly, you can pass a javascript array that has a function in the last index position:
[function() {}]
the above example becomes:
angular.module('test').run(['myValue', function(a) {console.log(a);}]);
There are many build tools that perform automatic annotation (ng-annotate), and is always suggested run the angularjs in strict-di mode.
Hope it helps
The first n elements of the array are factory names and you should use something that is registered at this point. Here - router - which has its own provider (the thing that can setup the router service). The config itself hasn't got too many options to choose from as it is parsed before your app is instantinated, hence you'll use providers and constants here. https://docs.angularjs.org/guide/providers
The last element of the array is the function whose arguments should correspond to the things you pass in the array. The names here are your choice, although keep in mind the order.
So, summing up, you can't rename the thingies in the quotation marks '$routeProvider', instead, know your app and what you are installing. But you can use your own names for them in the latter function($mynameforrouteprovider) but you have to keep them in order. Best if you use the same names that their author uses.
This JSBin isolates a problem I ran into in my code. I have a hierarchy of embedded models and a computed property (data) that is supposed to fire whenever a value at the very bottom of the chain changes (symbol). The example displays the property directly as well as the result of the computed property. A button changes the value on click. You'll see that it updates the property but the computed property doesn't fire. Why doesn't selectedAllocation.positions.#each.instrument.symbol work to trigger the computation when any instrument.symbol changes?
If the example seems contrived, it's only because I tried to abstract something that is more complex in reality, e.g. there is more than just one object in these arrays and data is necessary because another library expects a simple JS object in a particular format.
Note that #each only works one level deep. You cannot use nested forms
like todos.#each.owner.name or todos.#each.owner.#each.name.
http://emberjs.com/guides/object-model/computed-properties-and-aggregate-data/
You'll need to create an alias to bring symbol up one level (Not a coffeescript guy, hopefully you can read through the hacking, the positions alias below is for kicks and giggles, makes no difference).
App.Position = Ember.Object.extend({
instrumentSymbol: Em.computed.alias('instrument.symbol')
})
App.IndexController = Ember.ArrayController.extend
selectedAllocation: null
positions: Em.computed.alias('selectedAllocation.positions'),
data: (->
#get("positions").map (position) ->
symbol: position.get "instrumentSymbol"
).property "positions.#each.instrumentSymbol"
...
http://jsbin.com/bivoyako/1/edit
I’m using the new query params feature http://emberjs.com/guides/routing/query-params/ and trying to figure out an issue when using .property().
In the client side sorting example when I change the name of the methods sortProperties, or paged (I’ve added console output to each) they no longer execute when their observed property changes. The name of the method shouldn’t matter right?
http://jsbin.com/ucanam/5069/edit
You can't rename sortProperties, it's property of Ember.SortableMixin
In your example computed property sets sortProperties: [resultOfComutedProperty] and if you'll rename sortProperties will no reasons to fire it.
paged is just computed property, don't forget to rename it in handlebars template and all will work
Beginner Meteor/JS question:
When associating objects in Meteor I see small line of code that I'm not understanding. For example, post with associated comments.
var $body = $(e.target).find('[name=body]');
var comment = {
body: $body.val(),
postId: template.data._id
};
So get the content of the comment, put it in the variable "comment", and also create a postId to go into this comment so you know what post the comment belongs to. This postId is being called in with *'template.data._id'*
My questions are:
So you call template, then wouldn't you want to call the template name? Not data? Where is data coming from?
That aside, so you call data...and then ._id, are there other options to 'data'? IE
template.data.(option)
This isn't working for me, haha, *console.log(template.data._id);* is coming back undefined. So it's not grabbing the object ID as advertised. I'm sure I messed something up.
Here's the surrounding code if you need more context:
https://github.com/DiscoverMeteor/Microscope/blob/master/client/views/comments/comment_submit.js
Beginning with the easiest first, under your point 3 it should read:
console.log(template.data._id);
As to points 1 and 2, the key idea to note is that your code is being called inside of Template.commentSubmit.events({}). Inside of this object (the "{}"), you are working with an instance of the template in the document, including whatever data is being passed to that instance. In a different template, you will receive different data and hence template.data will consist of different keys and values. You can check out more in the documentation here, http://docs.meteor.com/#template_inst.
So in answer to your question, the reason you can invoke "data" rather than the template name is that the template name has already been provided by Template.commentSubmit. Note that inside of events({}), "this" will generally be equivalent to "template.data." So
console.log(template.data._id);
will generally be equivalent to
console.log(this._id);
The properties you can access on the data will always vary based on the instance received by the template. For example, if template.data consists of {_id: 1, name: "x", location: "y"}, you can retrieve these values by calling the keys, e.g. "template.data.name" or "template.data._id" etc. In your example, you are correct that you are setting postID to template.data._id.
The data arriving to the template comes from your Meteor.subscriptions. Hope this helps.
The template has a data context. When you use an {{#each}} block you are iterating through data, in this case posts.
So using template.data retrieves the data context for the template. It would refer to a post from where the comment form is. So template.data._id is the equivalent of this post._id (where post is the post you're commenting on).
The thing is I think this was removed from meteor. It was there a couple of versions back. I'm not sure about this but that's what I thought. I would have thought the correct code should be this._id. Where this ends up being the data context of the form (which would again be the post).
Could you check if that gives you undefined if you changed it out?
The .events method of a template takes in an event map:
http://docs.meteor.com/#eventmaps
The callbacks for each of the events (in this case 'submit form') can take two arguments. The first one 'e' is the javascript event object and the second one 'template' is the instance of the template where the event occurred. That template instance has a bunch of utility methods/properties (see http://docs.meteor.com/#template_inst) one of which is .data (see http://docs.meteor.com/#template_data). That .data property returns the data that the template was bound to (in your Microscope example it looks like it's bound to a comment object) and that object (in this case) has an _id property.
Note that the 'template' (little T) is not the same as Template (big T).
I am using Ember.js for my project, and there is a point when I have to remove all the contents or set every property to "" or null for an Ember.Object.
So what is happening is, within the template, there are handlebars tags that link to some of the objects properties ({{myProperty}}),so when the object is emptied or every property set to "" or null, this binding should still exist if the properties are updated to new values.
Is there a way to achieve this? Is there a way to maybe loop through all the properties quickly?
(started writing this thinking that eachAttribute is a method on Ember.Object, but it's on DS.Model instead. So...)
If your object happens to be an Ember Data DS.Model instance, there is the eachAttribute method, which takes a callback function. So one way to do what you're suggesting might be:
modelobj.eachAttribute(function(propName){
modelobj.set(propName, null);
});
The only other idea that springs to mind is instantiating a new "blank" instance of your object, and assigning it in the old one's place...I think handlebars bindings would update properly in most cases if you did that.
Would it work for your application to use an {{#if}} statement in the template to conditionally show/hide your properties?
Like this:
{{#if view.showStuff }}
<p>{{view.myProperty1}}</p>
<p>{{view.myProperty2}}</p>
<p>{{view.myProperty3}}</p>
{{else}}
<p>Not showing content</p>
{{/if}}
If showStuff is true then your properties will be rendered, otherwise it will display the other html.
Example http://jsfiddle.net/cteegarden/rHafx/1/