BorisMoore / jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates
http://www.jsviews.com/#jsviews
MIT License
856 stars 130 forks source link

Move the tag property in views to before rendering, to enable "get current path" path scenario #400

Closed mcartmel closed 5 years ago

mcartmel commented 6 years ago

Hi, just wondering if there is an easy way to get the current full data path? Basically the same as what is returned by observeAll when a change event occurs, but inside a template. eg:

{{:~getPath}}
base.person[3].firstname
BorisMoore commented 6 years ago

The current object is not necessarily on a simple path from the root. You might have custom tags wrapping content and setting arbitrary context, or regular tags such as {^{for ~foo.bar(...)}} - where the ~foo.bar() helper returns some object that it gets/instantiates from somewhere.

If all you have is {{for a.b.c}} with simple paths, and tags like {{if}} which don't move the context, then such a path may make sense.

Given this complexity there is no built-in feature of that kind.

You can actually get at the View prototype and add a recursive helper method to the view object along these lines:

function getPath() {
  var view = this,
    parent = view.parent,
    path = "";
  if (view.isTop) {
    path = "root";
  } else {
    path = parent.getPath();
    if (parent._.useKey) {
      path += view.tag && view.tag.contentCtx !== true ? ("." + view.tag.tagCtx.params.args[0]) : "";
    } else if (parent.tag && parent.tag.tagName === "props") {
      path += "." + view.data.key;
    } else {
      path += "[" + view.index + "]";
    }
  }
  return path;
}
$.views.sub.View.prototype.getPath = getPath;

or use an equivalent helper ~getPath(#view) which steps up through the parent views, concatenating a path for simple scenarios...

However the above will not work correctly without making a small change to jsviews, which I will indeed include in the next update. (Changing the title of this issue accordingly):

Remove the line: newView.tag = tag; from here: https://github.com/BorisMoore/jsviews/blob/master/jsviews.js#L1616

and insert two copies of the same line here: https://github.com/BorisMoore/jsviews/blob/master/jsviews.js#L1612 and here: https://github.com/BorisMoore/jsviews/blob/master/jsviews.js#L1592

mcartmel commented 6 years ago

Thanks very much for this Boris. I have made the modifications and the method works well. I'm using it to create unique ID's for inputs etc. Cheers.

BorisMoore commented 5 years ago

This has been fixed in release v0.9.91.