0

I have an object like this

myObj = {
    "strPattern": "Name: #name#<br>Surname: #sname#<br>Location: #loc#",
    "name": "John",
    "sname": "Doe",
    "loc": "LA"
}

Now I need a function which will take my object and return it as a string with the help of its pattern.

Expected Result : "Name: John<br>Surname: Doe<br>Location: LA"

I couldn't do it with JavaScript's replace method and I dont know how to do it. Thank for your help.

By the way, number of subStrs can be dynamic. For example there are 3 subStrings in this example but it can be 5 or 10 for other objects. #age#, #gender#, etc...

user3253797
  • 183
  • 1
  • 7
  • I know you have an answer, but you may want to look at actual templating engines like ejs, handlebars, etc – Mark Kahn Feb 01 '14 at 09:29

5 Answers5

2

You can loop to an objects properties using the for (var key in myObj) structure. In every loop the key variable holds the name of each property and you can access its value with the myObj[key] variable.

An example of how you could use in your scenario could be like this.

var myObj = {
    "strPattern": "Name: #subStr1#<br>Surname: #subStr2#<br>Location: #subStr3#",
    "subStr1": "John",
    "subStr2": "Doe",
    "subStr3": "LA"
};

var html = myObj["strPattern"];

for (var key in myObj) {
   var obj = myObj[key];
    if(key !== "strPattern") {
        html = html.replace("#" + key + "#",obj);
    }
}

jQuery('#result').html(html);

I also made a jsfiddle with it.

Edit: As @Andreas mentioned in a comment, the order of accessing the properties is not guaranteed, I adjusted my code snippet accordingly.

Tasos K.
  • 7,669
  • 7
  • 38
  • 57
  • [Does JavaScript Guarantee Object Property Order?](http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – Andreas Feb 01 '14 at 09:21
  • 1
    @Andreas -- Although the specs say no, _every_ implementation says yes. But even so, I don't like this. `var html = myObj.strPattern` with `if( key === 'strPattern' ){ continue; }` is better. – Mark Kahn Feb 01 '14 at 09:23
  • your replace should be `html.replace( new RegExp( '#' + key + '#', 'g' ), obj ) )` to allow for multiple instances of the same pattern – Mark Kahn Feb 01 '14 at 09:27
  • @zyklus But it is not guaranteed and therefor you shouldn't rely on. I'm not aware of the current situation but there were times when the order was implemented differently ([v8 - Issue 164](http://code.google.com/p/v8/issues/detail?id=164)) – Andreas Feb 01 '14 at 09:30
  • @Andreas -- Eh, you can rely on it if you need to, as long as you're aware that it may break somewhere, at some point (even if that's very unlikely). Your page is more likely to break because JS is disabled than because of this – Mark Kahn Feb 01 '14 at 09:35
  • @zyklus that is a good point, using RegExp is a better approach. – Tasos K. Feb 01 '14 at 09:36
2

The following function can be used to improve performances. However, it's useless if you don't need to use the template multiple times.

function compile(tpl) {
    tpl = tpl.split(/#(.*?)#/);
    return Function('return [' + tpl.map(function (v, i) {
        if (i % 2) return 'this["' + v + '"]';
        return v && '"' + v.replace(/"/g, '\\"') + '"';
    }).join(',') + '].join("");');
}

Usage example :

var myObj = {
    "strPattern": "Name: #name#<br>Surname: #sname#<br>Location: #loc#",
    "name": "John",
    "sname": "Doe",
    "loc": "LA"
};

myObj.strPattern = compile(myObj.strPattern).call(myObj);

More interesting :

var tpl = '#first# #last#',
    compiled = compile(tpl);

compiled.call({ first: 'John', last: 'Doe' }); // "John Doe"
compiled.call({ first: 'Walter', last: 'White' }); // "Walter White"

More details here : https://stackoverflow.com/a/20886377/1636522.

Community
  • 1
  • 1
leaf
  • 14,210
  • 8
  • 49
  • 79
0

Another way to approach this, that works through only the replacements that appear in the string, would be:

var Stringify = function(obj){
  return obj.strPattern.replace(/#([a-z]+)#/gi, function(match,group){
    return obj[group] || match;
  });
};

var str = Stringify({
  "strPattern": "Name: #name#<br>Surname: #sname#<br>Location: #loc#",
  "name": "John",
  "sname": "Doe",
  "loc": "LA"
});

This also could be of interest to those wanting to use string.replace(pattern, function).

When did all browsers start supporting the String.replace(regexp, replacement_function)?

Community
  • 1
  • 1
Pebbl
  • 31,117
  • 6
  • 57
  • 63
0
myObj = {
    "strPattern": "Name: #subStr1#<br>Surname: #subStr2#<br>Location: #subStr3#",
    "subStr1": "John",
    "subStr2": "Doe",
    "subStr3": "LA"
}
function patternMatcher(myObj){
  strp = myObj.strPattern;
  pattern = strp.match(/#(.*?)#/g);

  for (key in pattern){
    origKey = pattern[key].substr(1,pattern[key].length-2);
    strp =  strp.replace(pattern[key],myObj[origKey])
  }
return strp;
}

console.log(patternMatcher(myObj)); 

Here's Your Code running example link

0
function getFilled(myObj){
  pattern = myObj.strPattern.match(/#(.*?)#/g);
  for (key in pattern){
    myObj.strPattern =  myObj.strPattern.replace(pattern[key],myObj[pattern[key].substr(1,pattern[key].length-2)])
  }
return myObj.strPattern;
}

console.log(getFilled(myObj)); 
arslion
  • 394
  • 5
  • 15