1

I have an object which at some points is four levels deep, however I want a function that will cope should more levels be introduced. I'm trying to write a function that will replaced elements such that <span class="ajax-parent1-parent2-parent3-value"></span> will be replaced with parent1.parent2.parent3.value.

The issue is that the depth is variable, so I could have something like <span class="ajax-parent1-value"></span> to be replaced with parent1.value.

Finally, it's not always the text to be replaced. Optionally, data-attr can specify an attribute to be used instead (through element.attr(<data-attr>, <value>)).

Currently, I'm iterating manually, however it isn't very clean so I was wondering if there is a better way to do it. This also doesn't work for greater than two levels deep.

function render(data) {
  $.each(data, function(parent, value) {
    $.each(value, function(element, value) {
      $el = $('.ajax-' + parent + '-' + element);
      $.each($el, function(key, el) {
        if ($(el).data('attr')) {
          $(el).attr($(el).data('attr'), value);
        } else {
          $(el).text(value);
        }
      }
    });
  });
}

Example object:

{
  "profile": {
    "username": "johnd",
    "bio": "Some example data about John",
    "website": "http://john.com",
    "profile_picture": "http://john.com/me.jpg",
    "full_name": "John Doe",
    "counts": {
      "media": 13,
      "followed_by": 26,
      "follows": 49
    },
    "id": "16"
  },
  "dashboard": {
    "script": {
      "tags": ["media"],
      "stats": {
        "liked": 0,
        "lastrun": "never",
        "duration": 0
      },
      "status": {
        "code": 0,
        "slug": "disabled",
        "human": "Disabled",
        "message": "Not running."
      }
    },
    "account": {
      "plan": "free",
      "created": 1419261005373,
      "updated": 1419261005373
    }
  },
  "serverInformation": {
    "serverName": "Johns API",
    "apiVersion": "0.0.1",
    "requestDuration": 22,
    "currentTime": 1419262805646
  },
  "requesterInformation": {
    "id": "redacted",
    "fingerprint": "redacted",
    "remoteIP": "redacted",
    "receivedParams": {
      "action": "getDashboard",
      "apiVersion": 1
    }
  }
}
9
  • class="ajax-parent1.value" it's a bad practise to use dot in class name Commented Dec 22, 2014 at 15:58
  • @Mohamed-Yousef The HTML doesn't matter, it all follows the pattern of <span class="ajax-<value in object>" where a new level is indicated with a -. Commented Dec 22, 2014 at 15:59
  • @demo Oops, that was a typo. Fixed. Commented Dec 22, 2014 at 15:59
  • If possible , can post an example data object ? Thanks Commented Dec 22, 2014 at 16:02
  • 1
    Split the task by two parts - Part 1- ensure each node which has to be visited gets visited. Part 2- ensure the appropriate action is taken for each visited node. You don't need to know the depth as you can use a recursive function. Please come up with a self containing sample demoing the most complex case. Commented Dec 22, 2014 at 16:53

2 Answers 2

0

Here is the solution I wrote:

function iterate(obj, stack) {
  for (var property in obj) {
    if (obj.hasOwnProperty(property)) {
      if (typeof obj[property] == "object") {
        iterate(obj[property], stack + '-' + property);
      } else {
        $group = $('.ajax' + stack + '-' + property);
        $.each($group, function(key, element) {
          if ($(element).data('attr')) {
            $(element).attr($(element).data('attr'), obj[property]);
          } else {
            $(element).text(obj[property]);
          }
        });
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Why don't you start from the HTML, so you only access the properties you actually want to render?

That way you can keep it quite simple (also note that this removes the need to nest HTML spans in the same order/depth as the data object, you can just place any HTML node anywhere. Just make sure you don't use class/node names more then once.

function parseData(data) {
    var $container = $('.ajax');

    $container.find("[class^='ajax-']").each(function(i, el) {
        var $el = $(el);
        if ($el.children().length === 0)
        {
            var nodes = $el.attr('class').split('-');
            nodes.shift();

            var node = data;
            for (var i = 0; i < nodes.length; i++) {
                node = node[nodes[i]];

                if (typeof(node) == "undefined") {
                    break;
                }
            }

            if ($el.data('attr'))
            {
                $el.attr($el.data('attr'), node);
            }
            else
            {
                $el.text(node);
            }
        }
    });
}

Fiddle here:

http://jsfiddle.net/ckcduLhn/5/

Comments

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.