3

The texts.json:

[{
  "PageTextKeyId": 1,
  "PageTextKeyName": "page-first-text",
  "PageTextValueName": "Lorem ipsum dolor sit amet"
}, {
  "PageTextKeyId": 2,
  "PageTextKeyName": "after-page-first-text",
  "PageTextValueName": "Consectetuer adipiscing elit"
}, {
  "PageTextKeyId": 3,
  "PageTextKeyName": "third-text-on-json",
  "PageTextValueName": "Sed diam nonummy nibh"
}, {
  "PageTextKeyId": 4,
  "PageTextKeyName": "this-is-the-forth",
  "PageTextValueName": "Euismod tincidunt ut laoreet"
}, {
  "PageTextKeyId": 5,
  "PageTextKeyName": "last-text-from-the-file",
  "PageTextValueName": "Dolore magna aliquam erat volutpat"
}]

The index.html:

<!DOCTYPE html>
<html>
    <head>
        <title>Text from JSON</title>
        <meta charset="UTF-8">
        <meta name="format-detection" content="telephone=no">
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    </head>
    <body>
        <div id="container" class="some-class">
            <p>[page-first-text] - [page-first-text]</p>
            <div id="creatives">
                <b>[after-page-first-text]</b>
                <div>
                    <span>
                        <i>[third-text-on-json]</i>
                    </span>
                </div>
            </div>
            <div class="holder">
                <div id="sfc">
                    <div id="designer">
                        <a href="#">[this-is-the-forth]</a>
                    </div>
                    <div id="developer">
                        <div>
                            <div class="designer-class">
                                <a href="#">
                                    <span>[last-text-from-the-file]</span>
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <script src="script.js" ></script>
        </div>
    </body>
</html>

This is just a sample html, it can also have lot's of [text-here] in a DOM without id or class.

The script.js:

(function() {
    var jsonRequest = new XMLHttpRequest();
    jsonRequest.open('GET', 'texts.json');
    jsonRequest.setRequestHeader("Content-Type", "application/json");
    jsonRequest.onload = function() {
        var jsonContent = JSON.parse(jsonRequest.responseText);

        /* NEED HELP HERE */

    }
    jsonRequest.send();
})();

I would like to replace the html string that starts & ends with "[" & "]" with the value inside the json file on-the-fly (only when I view the page on browser) not permanently.

Example output on browser:

...
   <body>
        <div id="container">
            <p>Lorem ipsum dolor sit amet</p>
            <div id="creatives">
                <b>Consectetuer adipiscing elit</b>
                <div>
                    <span>
                        <i>Sed diam nonummy nibh</i>
                    </span>
                </div>
            </div>
            <div id="holder">
                <div id="sfc">
                    <div id="designer">
                        <a href="#">Euismod tincidunt ut laoreet</a>
                    </div>
...

I was hoping for maybe a regex solution, something like:

var everyDom = document.getElementsByTagName('*');
for (var i=0; i<everyDom.length;i++) {
    /*
    check with regex if dom value starts with "[" and end with "]"
    if true replace value with json value from key-name
    else go and look for other doms
    */
} 
2

3 Answers 3

1

Thanks to alex for the matchText function.

I would like to suggest the following key-value object format as your JSON data. It will be simpler, fast and uses less network bandwidth.

You can use this function to convert your data to a key-value object format.

var map = {};
data.map(function(d) {
  map[d.PageTextKeyName] = d.PageTextValueName;
});

Please see this jsFiddle

// parsed JSON data from response
var map = {
    "page-first-text": "Lorem ipsum dolor sit amet",
    "after-page-first-text": "Consectetuer adipiscing elit",
    "third-text-on-json": "Sed diam nonummy nibh",
    "this-is-the-forth": "Euismod tincidunt ut laoreet",
    "last-text-from-the-file": "Dolore magna aliquam erat volutpat"
};

// find matching text in given nodeand apply the callback for replacement
var matchText = function(node, regex, callback, excludeElements) {
  excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
  var child = node.firstChild;
  do {
    switch (child.nodeType) {
      case 1: // other html elements
        if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) {
          continue;
        }
        // iterate next element
        matchText(child, regex, callback, excludeElements);
        break;
      case 3: // TextNode
        child.data = child.data.replace(regex, callback);
        break;
    }
  } while (!!(child = child.nextSibling));
  return node;
};

matchText(document.body, /\[(.*?)\]/gi, function(match) {
  var key = match.substring(1, match.length-1);
  return (!!map[key]) ? map[key] : match;
});

Explanation.

matchText function iterates the children of given node from firstChild and its siblings(via nextSibling ).

When the NodeType is an Html Element (case 1), it calls matchText to iterate node recursively.

When the NodeType is a TextNode (case 3), it calls the callback function to replace the matching string.

/\[(.*?)\]/gi is a RegExp to find anything that starts from a '[' up to ']'.

Sign up to request clarification or add additional context in comments.

4 Comments

wow this works great! however, can you please add explanation how this scripts works & how can i remove the extra <span class="replace"> on it? also there is an error, when a DOM has this <p>[text-one-here] - [text-two-here]</p> the next DOM that have [text-here] doesn't convert.
I have updated the fiddle to fix the bug. Please check.
hi @SenJacob thank you for your solution, but I have a problem, when I use it on my page, I'm having an error "Uncaught TypeError: Cannot read property 'nodeType' of null" you can check here: jsfiddle.net/kdgop88y/4
Thank you very much for this solution, greatly appreciated.
1

You could give the element you want the data in an id.

<div id="creatives">
   <b id="firstText">Consectetuer adipiscing elit</b>
</div>

And in your JavaScript you do can access this element like this:

document.getElementById("firstText").innerHTML = YOUR JSON ELEMENT VALUE

1 Comment

adding "ID"s on every string is not a good solution. what if i have a big html file with lot's of [text-here], i need to give every single string an "ID"? i was hoping for maybe a regex solution, something like: var everyDom = document.getElementsByTagName(''); for (var i=0; i<everyDom.length;i++) { / check with regex if dom value starts with "[" and end with "]" if true replace value with json value from key-name else go and look for other doms */ }
0

edit: Updated solution to reflect specifications

You didn't specify how much control you have over the HTML template (I assume all) and how much variance there is in json file contents, but I would attach id or class properties to relevant elements in HTML template and then use document.getElementById or document. getElementsByClassName. Then you can replace element HTML

  ...
  <b class="placeholder">[after-page-first-text]</b>
  ...

(function() {
  // find all elements with targeted class
  var placeholderElements = document.getElementsByClassName('placeholder');

  function replaceText(keyName, content) {
    for (var j = 0; j < placeholderElements.length; j++) {
        // see if text content matches [keyName]
        if(placeholderElements[j].textContent === '[' + keyName + ']') {
          console.log('found element', keyName);
          placeholderElements[j].innerHTML = content;
        break;
      }
    }
  };

  /* READ JSON */

  for (var i = 0; i < jsonContent.length; i++) {
    replaceText(jsonContent[i].PageTextKeyName, 
    jsonContent[i].PageTextValueName);
  };
})();

Please see this fiddle for a demo: https://jsfiddle.net/Perttu/wndL4fas/

3 Comments

thanks for your solution, but as i mentioned on @Potato 's answer, adding "ID"s per string is not a good solution. because sometimes the html have lots of [text-here], adding "ID"s in all of them is i think a wrong approach. i was thinking maybe we can use regex to check the dom if it starts and end with "[" & "]" then replace the whole value from json.
@PerttuHeliseva thank you very much on your quick answer, but as i mention on my first comment on your solution, we can't add ID's in all dom's who has [text-here], because sometimes, we have something like <p>[text-one], [text-two], [text-three] or more</p>.
Then as far as I can see with all these limitations (which would have been very useful to have in the original question, by the way) your viable, if ineffective option is to replace all text occurrences in DOM: document.body.innerHTML = document.body.innerHTML.replace('[' + keyName + ']', content);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.