Reputation: 183
In a page I call external js file and its includes a dictionary. I want to replace element text by their attiributes.
<p data-text="dict.dataP"></p>
<p data-text="dict.data.P2"></p>
I want to fill it with external file dict
var dict = {
"dataP1": "this is my p text",
"data" : {
"p2": "my another paragraph"
},
};
I tried to use as this
$.each(function () {
if ($(this).attr("data-text").length > 0) {
$(this).html(
$(this).attr('data-text') /*we got a problem here. it returns string*/ );
}
});
codePen here: codepen.io
JSFiddle here jsfiddle.net
edited dict. we have dictionary in dictionary.
Upvotes: 2
Views: 174
Reputation: 36005
There are a few things that you should change to get this working, taking Jimbo's answer and adding a few other things:
var dict = {
"dataP": "this is my p tag text"
};
$('[data-text]').each(function () {
if ( $(this).data("text") ) {
var dictAttr = $(this).data("text");
if ( dictAttr && dict[dictAttr] ) {
$(this).html( dict[dictAttr] );
}
}
});
You should also change your mark-up to make things easier (expecially if you are only dealing with one dict
object):
<p data-text="dataP"></p>
With the above changes you should get things working as you expect.
Rather oddly I'm actually working on a framework for string-based object navigation as we speak. However the codebase if far too complicated to just tack on the end of a stackoverflow answer. As an addition to my comment I realised there is a third option which might be the best of both worlds (depending on what you need).
:: eval
I don't recommend this method, but it can't be argued with for simplicity — the following is a snippet from the code above and should replace that part:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP'
var ref; eval('ref='+dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
The problem with the above is that eval
will evaluate any JavaScript - so all an attacker would have to do is find a way to add a data-text
attribute to something on your page and they would be able to execute any JavaScript they liked.
:: string-based navigation
The following is a simple function that could be improved, but should give you the idea:
function navigate( obj, path ){
var cur = obj, bits = path.split('.');
for ( var i=0, l=bits.length; i<l && cur; i++ ) {
cur = cur[bits[i]];
}
return cur;
}
Using the above you can navigate your dictionary structure - be aware because you start your 'navigation path' with a particular var name (i.e. dict
) you'll have to place your dictionary one level down of the object you wish to traverse; this is the reason for {dict:dict}
. To support multiple dictionaries you'd just need to extend that object like so {dict:dict,dict2:dict2}
— again the following is a snippet and should replace the original code:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP.test'
var ref = navigate({dict:dict}, dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
:: third option - simplify your dictionary
The third option is probably the most optimal, but means that the dictionary can't be modified in realtime (or at least not easily). Basically before you run the rest of your code, push your dictionary through a parsing function that modifies it's structure:
var dict = {
"dataP": "this is a test",
"forms": {
"inputLabel": "this is a second level"
}
};
function simplifyDict( obj, target, path, subpath ){
if ( !target ) { target = {}; }
if ( !path ) { path = ''; }
for( var i in obj ) {
subpath = (path ? path + '.' : '') + i;
if ( typeof obj[i] == 'object' ) {
simplifyDict( obj[i], target, subpath );
}
else {
target[subpath] = obj[i];
}
}
return target;
}
dict = simplifyDict( dict );
The above simplify function should return something like:
{
"dataP" : "this is a test",
"forms.inputLabel" : "this is a second level"
}
Then all you need to do is use my original code right at the top of this answer. Instead of converting your strings to separate object properties and navigating the dictionary, you've switched the dictionary to be a string-based lookup... so now you can just use strings directly i.e. dict['forms.inputLabel']
Upvotes: 2
Reputation: 6404
You'd like to set the text from the dictionary to the element with matching data attribute, right?
Try this:
var dict = {
"dataP": "this is my p tag text",
"dataDiv": "dummy div"
};
$('p').each(function () {
var data = $(this).data('text');
$(this).html(dict[data.split('.')[1]])
});
Upvotes: 2
Reputation: 26534
In order to access the data attribute, use:
$(this).data('text');
Text is the part after the hyphen within your attribute declaration.
Upvotes: 5