L20n.js: localize dynamically created strings - javascript

In my app I can localize most of strings via tags, as it is described in l20n.js docs. But sometimes I have to localize dynamycally created strings. Like: document.getElementById(id).innerHTML = "some text";
I use Polymer and custom web components, so the main goal is to create one function for any localization case.
If i try document.l10n.get(string);, I get TypeError: document.l10n.get is not a function.
What is the best way to do it? Could not find the solution in official docs.

Since document.l10n is an instance of the L20n's View class, you can use the formatValue and formatValues methods for your use-case. Please see the documentation for details.
Both methods return promises so you'll need to do something like the following:
document.l10n.formatValue('hello', { who: 'world' }).then(
hello => document.getElementById(id).textContent = hello
);
You can assign to textContent or innerHTML. Keep in mind that L20n allows for HTML in translations and it only sanitizes them when using the declarative data-l10n-id approach. So if you want to manually assign to innerHTML you might want to make sure you trust the content of the translations. In the future I'd like to add a special API to apply translations to DOM elements using the same sanitization as the declarative method (bug 1228021).

Related

What does .$ mean in javascript

I was in the console trying something when i saw that the .$ can be used along with the document object to access the elements. But i don't know what it actually does.
example :-
After some detective work, my guess it is a special Polymer component property:
Automatic node finding
Polymer automatically builds a map of statically created instance nodes in its local DOM, to provide
convenient access to frequently used nodes without the need to query
for them manually. Any node specified in the element's template with
an id is stored on the this.$ hash by id.
I am not familiar with Polymer, and it is very difficult to find (recent) documentation on this property.
However I believe my guess is correct based on the description above and the screen shot below. As you can see, if you add another . after the $ you get a list of suggested properties. These are all ids in the DOM:
I guess that may be any global object under jquery. Exactly, I don't have any experience with .$ but surf the official docs of Jquery, it may help or another possibility is that it is something coming from backend of from database. There may be a lot of reason. Hope, it helps..
This should be a property added to the element but is not anything special.
An example would be like
let a = {};
a.$ = {
b: 1,
c: 2
};
console.log(a.$);
This will also give you the object properties of $ in a.
A bonus fun fact is, in Javascript, emoji is also valid as property name, and therefore
let a = {};
a.$ = {
"😍": 1,
"😎": 2
};
console.log(a.$["😍"]);
also works

augmenting a jQuery object with custom properties

In my app, I have a number of jQuery objects which are kept in memory. That is, they don't get regenerated by another selector search. Also, they are local to the module.
const jQthing = $('#thing');
Is there any reason not to add custom properties to this object?
jQthing.title = 'All Things';
I know I can use the data dictionary but this looks a bit clumsy, especially
when retrieving a method. Would this be a bad design, or bad style?
Thanks
You can definitely do this, but you just need to be careful that the property that you add does not clash with any properties or functions that the jquery object would have. And that is why I wouldn't recommend that.
Instead, you would probably be better served wrapping the jquery object in an object and then make your own properties off of that. So for example something like below would do what you want, plus avoid any possible collisions.
var objectWrapper = {
jQthing: $('#thing'),
title: 'All Things'
}
So now you can use it like this objectWrapper.jQthing.fadeIn() or objectWrapper.title, without any worries.

Howto: generic test to see if widgets call this.inherited succesfully?

I maintain a custom library consisting of many dijit widgets at the company I work at.
Many of the defects/bugs I have had to deal with were the result of this.inherited(arguments) calls missing from overriden methods such as destroy startup and postCreate.
Some of these go unnoticed easily and are not always discovered until much later.
I suspect I can use dojo\aspect.after to hook onto the 'base' implementation, but I am not sure how to acquire a handle to the _widgetBase method itself.
Merely using .after on the method of my own widget would be pointless, since that wouldn't check whether this.inherited(..) was inded called.
How can I write a generic test function that can be passed any dijit/_WidgetBase instance and checks whether the _widgetBase's methods mentioned above are called from the widget when the same method is called on the subclassing widget itself?
Bottom-line is how do I acquire a reference to the base-implementation of the functions mentioned above?
After reading through dojo's documentation, declare.js code, debugging, googling, debugging and hacking I end up with this piece of code to acquire a handle to a base method of the last inherited class/mix-in, but I am not entirely happy with the hackiness involved in calling getInherited:
Edit 2 I substituted the second param of getInherited with an empty array. While I actually get a reference to the method of the baseclass using aspect doesn't work. It appears this approach is a bust.
require(['dijit/registry','dojo/_base/declare','mycompany/widgets/widgetToTest'],
function(registry,declare,widgetToTest)
{
var widget = registry.byId('widgetToTestId');
var baseStartup = getBaseMethod(widget,'startup');
function getBaseMethod(widget,methodName){
return widget.getInherited(methodName,[]);
}
//This is the method body I want to use .after on to see if it was called, it returns the last overriden class in the array of inherited classes. (a mixin in this case, good enough for me!)
alert(baseStartup);
});
I have given up trying to use dojo/aspect.
I have instead opted to modify the code of our custom base widget to incorporate snippets such as the one below. They are automatically removed when creating a release-build in which console-calls and their content are removed:
console.log(
function(){
(this._debugInfo = this._debugInfo|| {}).postCreate=true;
}.call(this)
);
A simple method in boilerplate code I added near the unittests is available so that I can call it on all mycompany.widgets.basewidget instances in their respective unittests.

Wrapping a DOM element inside a JavaScript object

I've noticed a common pattern in the JavaScript I've been writing and was wondering if there is already a pattern out there that defines something similar as best practice? Essentially, it's how to get a DOM element and wrap it inside / associate it with a JavaScript object. Take this example, where you need a filter in your web app. Your page looks like this:
<html>
<head></head>
<body>
<div id="filter"></div>
</body>
</html>
You'd then wrap the element like so:
var myFilter = new Filter({
elem: document.getElementById('filter'),
prop: 'stacks-test',
someCallback: function() {
// specify a callback
}
});
And the JavaScript (where spec is an object passed to the constructor):
var Filter = function(spec) {
this.elem = spec.elem;
this.prop = spec.prop;
this.callback = spec.someCallback;
this.bindEvents();
};
Filter.prototype.bindEvents = function() {
var self = this;
$(this.elem).click(function(e) {
self.updateFeed();
};
};
Filter.prototype.updateFeed = function() {
this.prop; // 'stacks-test'
this.callback();
// ...
// code to interact with other JavaScript objects
// who in turn, update the document
};
What is this kind of approach called, and what are the best practices and caveats?
You might be interested in Dojo's widget library, Dijit - if I'm understanding your question correctly, it essentially does what you're asking, and a whole lot more.
In Dijit, a widget essentially encapsulates a DOM node, its contents, any JavaScript that defines its behavior, and (imported separately) CSS to style its appearance.
Widgets have their own lifecycle, registry, and events (including many which simply map to DOM events on a node within the widget, e.g. myWidget.onClick could effectively call myWidget.domNode.onclick).
Widgets can (but don't have to) have their initial contents defined in a separate HTML template file, through which it's also possible to bind events on nodes within the template to widget methods, as well as set properties on the widget that reference particular nodes in the template.
I'm barely scratching the surface here. If you want to read more on this, you can start with these reference pages:
http://dojotoolkit.org/reference-guide/dijit/info.html
http://dojotoolkit.org/reference-guide/dijit/_Widget.html (the base that all widgets extend)
http://dojotoolkit.org/reference-guide/dijit/_Templated.html (RE the HTML templating)
http://dojotoolkit.org/reference-guide/quickstart/writingWidgets.html (useful information when starting to write your own widgets)
http://dojotoolkit.org/reference-guide/dijit/ (for a bunch more info)
All said, I don't know what you're ultimately aiming for, and maybe this is all a bit much for your purposes (considering I'm throwing an entire other library at you), but figured it might pique your interest at least.
Continuing from my comment on the question, jQuery is a potential tool for the job, as it already provides some of the foundations for what you're after. However, having said that, it does introduce complexities of its own, and further, not all "jQuery ways" are equal. I'll suggest one way of using jQuery as your "object model", but it may or may not suit your needs.
First things first. The philosophy of jQuery is that you start everything by selecting the element first, using $(), or equivalently jQuery(). All operations conceptually begin with this. This is a slightly different way of thinking compared to creating an object that wraps an element and keeping a reference to that wrapper, but essentially this is what jQuery does for you. A call to $('#some-id') grabs the element with id of "some-id" and wraps it in a jQuery object.
One way: Write "Filter" plugins.
Replace your constructor with a initFilter() jQuery method. You can do this by modifying the jQuery prototype and using the jQuery object as your wrapper. jQuery's prototype is referenced by jQuery.fn, so:
jQuery.fn.initFilter = function (prop, callback) {
// Save prop and callback
this.data('filter-prop', prop);
this.data('filter-callback', callback);
// Bind events (makes sense to do this during init)
this.click(function () {
$(this).updateFeed();
});
};
Then do a similar thing for updateFeed():
jQuery.fn.updateFeed = function () {
this.data('filter-prop');
this.data('filter-callback')();
});
And use it like this:
$('#filter').initFilter(prop, callback);
Note that updateFeed can simply be in-lined into the click handler to prevent unnecessary pollution of the jQuery namespace. However, one advantage of using jQuery like this is that you do not need to keep a reference to the object if you need to invoke some function on it later, since jQuery ties all references to actual elements. If you'd like to call updateFeed programmatically, then:
$('#filter').updateFeed();
will then be invoked on the correct object.
Some things to consider
There are certainly downsides to this method. One is that all properties, which we've saved against the element using .data(), are shared between all jQuery functions that act on that element. I've attempted to alleviate this by prefixing the property names with "filter-", but depending on the complexity of your object(s), this may not be suitable.
Further, this exact method may not be so suitable for objects that require a lot of manipulation (i.e. objects with many functions) since all of these functions become common to all jQuery objects. There are ways to encapsulate all this which I won't go into here, but jQuery-ui does this with their widgets, and I'm experimenting with yet another alternative in a library I'm creating.
However, pulling back a bit, the only reason I suggested using jQuery in the first place is that your Filter object appears to be heavily tied to the DOM. It binds events to the DOM, it modifies the DOM based on user interaction, basically it appears to live in the DOM, so use something DOM-based, i.e. jQuery.

What is the correct way to store data in the DOM

I have recently been using the title tag in various HTML elements to store data in JSON format in the DOM.
Is this a bad approach (I am assuming it is)? What is the correct way to accomplish this that works well with jQuery? By "works well" I mean
$("myButton").click(function (e) {
var myData;
eval("myData=" + $(this).attr("title"));
});
Works pretty well but again I am assuming there is a better way to do this no?
PS: BTW how does the title tag of HTML elements actually work? I cant seem to find where it actually ends up getting used?
PSS: Can I also get a jQuery based and Non jQuery response? (Sorry to be fussy)
eval("myData=" + $(this).attr("title"));
This is almost a legal reason to slap you! (j/k)
You should use your own namespace object to store data "globally". In that context, globally means only global in your application code and not using the global object (window in a browser).
var my_application = {};
$('myButton').click(function() {
my_application.myData = $(this).attr('title');
});
This is a very basic strategy of course. In your particular case, you can also use jQuery's .data() method to attach data to a DOM node.
$('myButton').click(function() {
$.data(this, 'myData', this.title);
});
Ref.: .data(), jQuery.data()
In your example, I'd suggest doing the following which does not expose you to the security risks of 'eval':
myData = JSON.decode($(this).attr("title"));
In general it's a valid approach to holding non-secure data. You have a number of other options too:
Use JQuery's .data() methods:
myData = $this.data("foo");
In HTML5 you now can use custom data attributes (Eg "") as an attribute on any element. http://html5doctor.com/html5-custom-data-attributes/
You could use Local Storage if you know it is available. http://dev.w3.org/html5/webstorage/
You could use Backbone.js on top of Jquery to give you a more abstracted way of handling your data as Models. http://documentcloud.github.com/backbone/
use jquery data()
The jQuery.data() method allows us to
attach data of any type to DOM
elements in a way that is safe from
circular references and therefore free
from memory leaks. jQuery ensures that
the data is removed when DOM elements
are removed via jQuery methods, and
when the user leaves the page. We can
set several distinct values for a
single element and retrieve them
later:
jQuery.data(document.body, 'foo', 52);
In the jQuery world it is usually said to be a best practice to use the metadata plugin as it is an official jQuery plugin and also supports HTML5 data attributes. For more info you could look at this http://docs.jquery.com/Plugins/Metadata/metadata

Categories