Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binding to computed functions: onBind callback called twice. If computed function has no setter , "... is not a function" exception thrown #451

Closed
AlexxVS opened this issue Dec 15, 2020 · 6 comments

Comments

@AlexxVS
Copy link

AlexxVS commented Dec 15, 2020

Hi,
Please take a look at this abstract case:

<body>
    <div id="text1">
    </div>

    <script type="text/javascript">

        $(function() {
            $.views.tags({
                tag1: {
                    template: `<div>{{:~arg1}}</div>`,
                    bindTo: [0, "param1"],
                    linkedCtxParam: ["arg1", "param1"],
                    onBind: function() {
                        console.log("tag1.onBind");
                    }
                }
            });
            $.views.viewModels({
                vm: {
                    getters: ["Prop1"]
                }
            });
            let m = $.views.viewModels.vm.map({Prop1: 1234});
            let tmpl = $.templates("{^{tag1 Prop1() param1=~util1(1) /}}");
            let utils = {
                util1: function(a) { return 1; }
            };
            tmpl.link("#text1", m, utils);
        });

    </script>
</body>

With JsViews versions 1.0.5 and earlier this worked, but starting from 1.0.6 and up to 1.0.9 the "view.ctxPrm(...) is not a function" exception is thrown. Now let's remove "Param1" from bindTo and linkedCtxParam:

<body>
    <div id="text1">
    </div>

    <script type="text/javascript">

        $(function() {
            $.views.tags({
                tag1: {
                    template: `<div>{{:~arg1}}</div>`,
                    bindTo: [0],
                    linkedCtxParam: ["arg1"],
                    onBind: function() {
                        console.log("tag1.onBind");
                    }
                }
            });
            $.views.viewModels({
                vm: {
                    getters: ["Prop1"]
                }
            });
            let m = $.views.viewModels.vm.map({Prop1: 1234});
            let tmpl = $.templates("{^{tag1 Prop1() param1=~util1(1) /}}");
            let utils = {
                util1: function(a) { return 1; }
            };
            tmpl.link("#text1", m, utils);
        });

    </script>
</body>

Now the exception is not thrown, but onBind callback method is called twice. With versions prior 1.0.6 onBind is called only once.

@BorisMoore
Copy link
Owner

BorisMoore commented Dec 18, 2020

Thank you very much for posting this. It's a good catch. I'll need to do some investigation... I'll let you know...

@BorisMoore
Copy link
Owner

Here is a potential update that should address your issues. Can you test that it works correctly for you?

jsviews.zip

Incidentally, your example is data-linking to util1(), as if it was a computed observable, but for the binding to work, it needs an associated setter function. See https://www.jsviews.com/#computed@getset.

For example, you could write:

let tmpl = $.templates("{^{tag1 Prop1() param1=~hlp.util1(1) /}}");
let utils = {hlp: {
    util1: function(a) {
      return this._util1;
    },
  _util1: "initUtil1"
}};
utils.hlp.util1.set = function(val) {
  this._util1 = val;
};
tmpl.link("#text1", m, utils); 

If you provide a setter, as above, the "view.ctxPrm(...) is not a function" exception will not be thrown.

But with the jsviews.js update provided there will no longer be any exception, even if you don't provide a setter. (Though of course two-way binding will not work unless there is a setter defined...)

Let me know if this works for you...

@AlexxVS
Copy link
Author

AlexxVS commented Dec 30, 2020

Thank you, Boris. The update resolves both throwing the exception and double onBind event.

@BorisMoore
Copy link
Owner

Thanks for confirming. I except to include this in the upcoming version 1.0.10.

@BorisMoore
Copy link
Owner

The fix concerns two issues:

  • Binding to a computed function with no getter, such as <input data-link="name()"/> with name.set undefined leads to an exception "name is not a function".
  • Tag two-way binding to a computed observable, such as {^{mytag name()/}} can trigger onBind callback twice.

@BorisMoore BorisMoore changed the title Helpers in the custom tag parameters and onBind callback Binding to computed functions: onBind callback called twice. If computed function has no setter , "... is not a function" exception thrown Jan 3, 2021
BorisMoore added a commit to BorisMoore/jsviews.com that referenced this issue Jan 10, 2021
Minor bug fixes:

See BorisMoore/jsviews#451

- Binding to a computed function with no getter, such as <input data-link="name()"/>
  with name.set undefined leads to an exception: "name is not a function".
- Tag two-way binding to a computed observable, such as {^{mytag name()/}}
  can trigger onBind callback twice.
BorisMoore added a commit to BorisMoore/jsrender that referenced this issue Jan 10, 2021
Minor bug fixes:

See BorisMoore/jsviews#451

- Binding to a computed function with no getter, such as <input data-link="name()"/>
  with name.set undefined leads to an exception: "name is not a function".
- Tag two-way binding to a computed observable, such as {^{mytag name()/}}
  can trigger onBind callback twice.
BorisMoore added a commit that referenced this issue Jan 10, 2021
Minor bug fixes:

See #451

- Binding to a computed function with no getter, such as <input data-link="name()"/>
  with name.set undefined leads to an exception: "name is not a function".
- Tag two-way binding to a computed observable, such as {^{mytag name()/}}
  can trigger onBind callback twice.2
@BorisMoore
Copy link
Owner

Fixed in release v1.0.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants