ractivejs/ractive

Different keypath resolutions between template and Ractive.set

Closed this issue · 4 comments

Hi,

Something like set('~/foo', 'bar') actually sets a variable named ~/foo while on the other hand templates consider ~/foo to be the foo of the root scope.

It leads to akward situations like this:
http://jsfiddle.net/2wkrx8ye/1/

I remember struggling with this too. Basically restricted references are only for templates and api calls always go from the root of the instance down.

The caveat to this is apis that find data (get, observe) will look up the context stack if the component is non-isolated and the data is not found locally. Conceptually, once the data is found (via api or template) a mapping exists within the component and subsequently a set operation will find the data as local.

I think there are two things to do:

  • Add note to docs (ractivejs/v0.x#208)
  • Add a warning when api calls use restricted refs (Have added better error label to this issue)

I just bumped into this too. I was wondering about two things:

  • Would it make sense to check for restricted references for API calls and adjust them? I do things like {{#each ~/foo}}<button on-click="splice('~/foo', @index, 1)">Remove</button>{{/each}} before I catch that the splice keypath isn't valid. It seems fairly harmless to strip off the '~/'. For non-root restricted references...

  • Maybe we could have an option for the API calls to specify an element on which to base the lookup. Seems like it might be handy for decorator and/or manual JS things (like a scroll listener, which sometimes must be on document or window to be useful) e.g. ractive.get('.name', { anchor: document.getElementById('some-id') }).

    Perhaps, taken from the other side, it would be nice to have a utility/helper to merge (resolve? normalize?) keypaths outside of Ractive so that could become something like ractive.get(Ractive.join(Ractive.getNodeInfo(document.getElementById('some-id')).keypath, '.name')) or maybe something a little more helpery and less verbose.

I think it's quite ok to leave the getters/setters like this, always relative to the root. Once you know it it's ok, and changing it would probably break lots of users code out there.

On the other hand, issuing a warning would definitely be great when you use ~/, .. or other shortcuts.

@evs-chris hi, I think that would mislead the user even more in the sense that they'll think the getters/setters will behave like references in template. Which they do not, and would just add confusion. On the other hand, changing/extending the getter/setters behavior would break lots of existing code. Therefore, I'm definitely more in favor of just issuing a warning rather than tweaking the getter/setters.

I like the idea of shouting a warning (or even throwing an error) too - I'm really into the idea of using errors and warnings as a way to guide people in these potentially confusing situations towards documentation that explains design decisions. That way people get a clearer understanding of how Ractive thinks about the world. Of course, that's predicated on there being decent documentation! So 👍 to ractivejs/v0.x#208.

@evs-chris yes, keypath join helper might be a good idea:

// could work like path.resolve in node...
Ractive.join( 'foo', 'bar' ); // 'foo.bar'
Ractive.join( 'foo', './bar' ); // 'foo.bar'
Ractive.join( 'foo', '../bar' ); // 'bar'
Ractive.join( 'foo', 'bar', '~/baz' ); 'baz'
Ractive.join( 'items', 4 ); 'items.4'

// but could also shortcut the Ractive.getNodeInfo use case - this...
Ractive.join( element, 'active' );

// could be equivalent to this:
Ractive.join( Ractive.getNodeInfo( element ).keypath, 'active' );