canjs / can-view-scope

Scope management for view engines
https://canjs.com/doc/can-view-scope.html
MIT License
4 stars 0 forks source link

notContext scopes should be readable using ../ #185

Closed phillipskevin closed 6 years ago

phillipskevin commented 6 years ago

@phillipskevin commented on Tue Sep 11 2018

This is broken with latest can-stache/can-view-scope because ../object is undefined:

import stache from "can-stache";
import DefineMap from "can-define/map/map";

const renderer = stache(`
    <div>
    {{#each(objects, object=value)}}
        <p>
        {{#each(../fields, field=value)}}
            {{../object[field]}}
        {{/each}}
        </p>
    {{/each}}
    </div>
`);

const data = new DefineMap({
    fields: ["one", "two"],
    objects: [{
        one: "a",
        two: "b"
    }, {
        one: "c",
        two: "d"
    }]
});

document.body.appendChild(renderer(data));

This works with

├─┬ can-stache@4.10.5
│ └── can-view-scope@4.7.1
phillipskevin commented 6 years ago

I think this is how this should work:

../. should skip special scope at location of . .././foo should skip special scope at location of . ../foo should not skip special scopes

phillipskevin commented 6 years ago

Putting this here to remind myself how I got this working later...

I got this working for both of the cases in:

{{#each(objects, object=value)}}
    {{#each(../fields, field=value)}}
        {{../object[field]}}
    {{/each}}
{{/each}}

../fields

Here is how the Scope looks when accessing ../fields:

  1. object - the normal scope created by {{#each objects}}
  2. { index } - the "special" scope created automatically by {{#each objects}}
  3. { object } - the "notContext" scope created by object=value in {{#each objects}}
  4. the "variable" scope
  5. { fields, objects } - the ViewModel

../object

Here is how the Scope looks when accessing ../object:

  1. field - the normal scope created by {{#each fields}}
  2. { index } - the "special" scope created automatically by {{#each fields}}
  3. { field } - the "notContext" scope created by field=value in {{#each fields}}
  4. object - the normal scope created by {{#each objects}}
  5. { index } - the "special" scope created automatically by {{#each objects}}
  6. { object } - the "notContext" scope created by object=value in {{#each objects}}
  7. the "variable" scope
  8. { fields, objects } - the ViewModel

Solution

Two things are needed to make this work:

  1. makeShouldSkipSpecialContexts should not skip notContext scopes after walking up the correct number of contexts based on the parentContextWalkCount.
  2. Keys like ../../foo should not use makeShouldExitAfterFirstNormalContext. They should only exit after seeing more normal contexts than the parentContextWalkCount.