incremental-bars icon indicating copy to clipboard operation
incremental-bars copied to clipboard

How to migrate inline HB-helpers

Open evil-shrike opened this issue 7 years ago • 5 comments

I have a HB helper, let's call data-bind. It's being used as:

<input {{data-bind name="value" prop="myprop"}}>

it creates two-way data-binding between an DOM-element and an object. During template execution it return html string. Like " id='x1' ". So the above code become <input id='x1'>. It allows later after template executed and its html inserted into DOM find the element and initialize binding. I understand that with incremeanl-dom two-way binding can be unneeded. But it's just an example of such a helper. So I'm trying to understand what helper should return in case of ibars backend. At first attempt I just tried to call: IncrementalDOM.attr("id", <generated_id>); in my helper. But it does nothing. In debugger I can see generated template 's code as:

IncrementalDOM.elementOpen("div", "idom-430", null, ""
    + (helpers['data-bind'] || (depth0 && HBX.get(depth0, 'data-bind')) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"data-bind","hash":{"prop":"myprop","name":"value",},"data":data})
    + "", ""))

So after my helper returned then IncrementalDOM.elementOpen is called with "undefined" in its last argument. Like: IncrementalDOM.elementOpen("div", "idom-430", null, "undefined") So ibars expects that helper returns a string for a single attr name. No more. But the last argument of elementOpen according to the docs is a dynamic list like ...args - http://google.github.io/incremental-dom/#api/elementOpen It seems logically to support returning an array and convert it into method's args.

Anyway what would be a possible workaround for such a case? What should helper return?

It's mentioned in READ that:

It is however totally possible to create an ad-hoc 'attribute' helper that does that directly on the DOM element. This is again something I never do as in my opionion returning html artifacts from templates smells of anti-pattern.

How such ad-hoc helper could be implemented?

evil-shrike avatar May 25 '18 19:05 evil-shrike

Let me add one more example

Givien a template:

<input {{data-bind value="myprop" }} />

Emitter returns:

"(IncrementalDOM.elementVoid("input", "idom-4", null, ""{{data-bind value="myprop"}}"", ""))"

After that Handlebars compiler processes and expand helpers into the following template function:

(function anonymous(container,depth0,helpers,partials,data
) {
  return (IncrementalDOM.elementVoid("input", "idom-4", null, ""
    + (helpers['data-bind'] || (depth0 && HBX.get(depth0, 'data-bind')) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"data-bind","hash":{"value":"myprop"},"data":data})
    + "", ""));
})

What I was thinking about is that emiiter should not wrap a helper call into quotes. Instead it could construct an array like this:

(IncrementalDOM.elementVoid.apply(null,["input", "idom-4", null].concat( {{data-bind value="myprop"}} || []) )

then helper could return an array like ["id", "x1"] and it will be passed into elementVoid. At the end we'll get a call like IncrementalDOM.elementVoid.apply(null,["input", "idom-4", null, "id", "x1"]. So that helpers will be able to pass arbitrary attr and their values into idom.

evil-shrike avatar Jun 01 '18 14:06 evil-shrike

the reason why the Emitter emits instructions in this way is because we don’t want to change Handebars at all - therefore we have to comply with its ways of dealing with the inputs passed to its compiler - which expected strings

On 1 Jun 2018, at 16:37, Sergei Dorogin [email protected] wrote:

Let me add one more example

Givien a template:

<input {{data-bind value="myprop" }} /> Emitter returns:

"(IncrementalDOM.elementVoid("input", "idom-4", null, ""{{data-bind value="myprop"}}"", ""))" After that Handlebars compiler processes and expand helpers into the following template function:

(function anonymous(container,depth0,helpers,partials,data ) { return (IncrementalDOM.elementVoid("input", "idom-4", null, "" + (helpers['data-bind'] || (depth0 && HBX.get(depth0, 'data-bind')) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"data-bind","hash":{"value":"myprop"},"data":data}) + "", "")); }) What I was thinking about is that emiiter should not wrap a helper call into quotes. Instead it could construct an array like this:

(IncrementalDOM.elementVoid.apply(null,["input", "idom-4", null].concat( {{data-bind value="myprop"}} || []) ) then helper could return an array like ["id", "x1"] and it will be passed into elementVoid. At the end we'll get a call like IncrementalDOM.elementVoid.apply(null,["input", "idom-4", null, "id", "x1"]. So that helpers will be able to pass arbitrary attr and their values into idom.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/atomictag/incremental-bars/issues/9#issuecomment-393900738, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGXKqPI-WLT9_oVZPCwUGlj1loyWw0Yks5t4VHBgaJpZM4UOgVA.

atomictag avatar Jun 01 '18 14:06 atomictag

Ok. Can I ask you how do you add event handlers for html elements? Handlebars itself doesn't have a notion of event handlers, helpers can't access dom nor vdom so they also can't add handlers. So what are options do you have? Just manually subscribe after patch?

evil-shrike avatar Jun 01 '18 14:06 evil-shrike

simplest and most generic way is to patch IncrementalDOM’s methods so that you can register ‘onOpen’ callbacks for 'elementOpen','elementOpenEnd','elementVoid',’text’ - which return you the node once it’s available

On 1 Jun 2018, at 16:52, Sergei Dorogin [email protected] wrote:

Ok. Can I ask you how do you add event handlers for html elements? Handlebars itself doesn't have a notion of event handlers, helpers can't access dom nor vdom so they also can't add handlers. So what are options do you have? Just manually subscribe after patch?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/atomictag/incremental-bars/issues/9#issuecomment-393905006, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGXKgzmsDUtmMYNLk97TPYYOxnDjUqQks5t4VUbgaJpZM4UOgVA.

atomictag avatar Jun 01 '18 14:06 atomictag

Such a callback would be called for every element right? But how can I tell from my template that for a particular button I need a click handler? I'd need to store some meta info and current context on a element and then later in that onOpen callback find them and subscribe to appropriate event. But we don't have any access to element in helpers.

evil-shrike avatar Jun 01 '18 15:06 evil-shrike