question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DotHTML 🔗 JavaScript

See original GitHub issue

We were discussing with @tomasherceg @martindybal how to connect JS code and dothtml markup.

We need/want several things:

  • Invoke DotVVM commands and staticCommands from Javascript code.
  • Invoke Javascript functions from event handlers.
  • Work with the ViewModel from JS
  • Have the functions scoped to one page. We would end up with crazy naming conventions and giant global declarations without the scoping.
  • Register some control options for the page (for example a sorting strategy for bp:AutoComplete)
  • Register postback handers for one page
  • Allow the same scoping for markup controls (and maybe also code controls)

We came with an idea, but there is still quite bit of issue to be solved (or ignored). You’d have a JavaScript object that would describe the client-side binding to the dothtml view. The describer object could be a default export of a module specified in a @js myPage dothtml directive.

There may be more objects registered for one page, the page should inherit from its master page and controls should inherit from the view they are used in.

Options

The following properties should be supported:

  • init(HTMLElement) - a function that is just invoked when the component or page is mounted into the DOM
    • this is not inherited into markup controls
    • the functions are combined as described in https://blog.ploeh.dk/2017/11/06/function-monoids/ (well, just invoked after each other)
    • basically equivalent to dotvvm.events.init.subscribe(() => ...) for pages
  • postbackHandlers: [PostbackHandler] - a collection of postback handlers that are applied by default to all commands in this scope.
    • basically a scoped version of dotvvm.globalPostbackHandlers
    • the order is implicitly that master page is before page, page is before markup control. But it may be overridden by before and after fields of the postback handler.
  • jsCommands: { [name: string]: (element: HtmlElement, args: [KnockoutObservable<any>]) } - a dictionary of client side command that may be invoked from the view (see JS Commands below)
    • the dictionaries are concatenated, in case of conflict page overrides master page, control overrides page.
  • requiredNamedCommands: [string] names of commands that should be imported from the DotHTML into a context
    • this property is there to overcome the issue that command and staticCommands can be only created from DotHTML markup. Also from C# (if you know how to do that), but certainly not from JS.
    • the command will be declared in the page/control in a special control <dot:NamedCommand Name=nameOfTheCommand Command="{command: DoSomething()}"
    • it will be later possible to invoke that command from JS.
    • It will return a promise that will contain the result of the command (as compared to the well known hidden button hack)
    • It will be possible to specify command arguments (as compared to the well known hidden button hack)
      • This point is quite important, but it’s TODO how to represent that in the control/binding typesystem.
    • This options is not inherited as described above, however the imported commands are inherited.
  • TODO: extend this to support multiple command of the same name (for example with different data context). This can be done easily by distinguishing them by a set of optional ids.

Context

All function invoked from the options (init and commands) will get additional argument with some context. The context will specifically contain:

  • importedCommands: { [name: string]: (args: [any]) => Promise<any>}
    • Contains the commands imported from <dot:NamedCommand ... controls
  • state: any - in this property, you can store the state of this module. It will be isolated from other instanced of the same markup control.

JS Commands

We have to figure out how to ergonomically invoke the JavaScript commands from the dothtml markup.

One option is to have jsCommand binding that will invoke exactly one command exported from the JS module. Syntax would be {jsCommand: nameOfTheCommand(Arg1, Arg2, ...)}, where nameOfTheCommand is any identifier and Arg1... are the well-known value binding expressions. This way, you can invoke a JS function easily while the arguments are still written in ergonomic way (at least compared to manually unwrapping every knockout observable). The arguments are always passed as knockout observables that may be writable.

Note that all data must be passed arguments, the command does not implicitly get a reference to data context. This is to avoid having commands hidden dependencies that can’t be reused anywhere.

Another options is to have a function _js.Invoke<ResultValue>("commandName", Arg1, Arg2, ...) that will be used from staticCommand. The behavior will be very similar as for the jsCommand.

There is always possibility to have both ways supported, as the first one is quite a bit more ergonomic and the second one it a more flexible…

Issues

  • If we let the user work with the client-side viewmodel directly, it will get to an invalid state very easily and don’t do any validation here. For example, when you insert your own (naively created) model, client-side validation will stop working (as you’d not specify $type).
    • IMHO, we can’t leave so many traps in the API. We’ll have to give the user a proxy object to the view model that will handle the validation
  • We’d like to keep the API strongly typed (in TypeScript), but that depends on the non-existent “TypeScript class generator”. This generator then depends on the dotvvm.compiler, which exists, but does not work very well (which is fixable) and needs to run after the build .NET (which is unfixable).

Edits: renamed commands to jsCommands, importedCommands to requiredNamedCommands, importedCommands to namedCommands, ExportCommand to NamedCommand

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:16 (16 by maintainers)

github_iconTop GitHub Comments

1reaction
tomashercegcommented, Dec 4, 2019

About the exported commands - I meant something like this:

<dot:Repeater DataSource="{value:Customers}">
  <dot:ExportCommand Name="cmd1" Command="{command: _root.Delete(_this.Id)}" />
</dot:Repeater>

The command would not be exported globally, but in the $context variable. Then, we can introduce a JS API to get the command reference:

var promise = dotvvm.exportedCommands.invoke("cmd1", sender);

The second argument would be a DOM element on which we’ll just ko.contextFor - I assume that in case of scoped commands the user will have some DOM element (button, link) anyway. And if the second argument is omitted, we can just look in the root scope.

0reactions
exyicommented, May 25, 2022

This was pretty much done in 3.0 and further extended in 4.0 with JsComponents and validation API. I don’t think there is much left to be done from this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Build a Simple Website with HTML, CSS, JavaScript - YouTube
Improve your skills in JavaScript, HTML, and CSS by building a ... Course created by @TheCoderCoder Resources: 🔗 Responsive Design for ...
Read more >
JavaScript Game Development Course for Beginners - YouTube
Learn to make 2D games with HTML, CSS & plain vanilla JavaScript, ... .co.uk/do... 🔗 More art assets: https://bevouliin.com/ ⭐️ Contents ...
Read more >
JavaScript Full Course for Beginners | 8 Hours - YouTube
Web development beginners should learn Vanilla JavaScript (what this course is) ... ... 🔗 DOM Lesson (chapter 21) HTML & CSS source code: ......
Read more >
JavaScript Programming Tutorial 3 - Manipulating HTML with ...
... Twitter - https://twitter.com/calebCurry 🔗 LinkedIn ... JavaScript Programming Tutorial 3 - Manipulating HTML with JavaScript.
Read more >
HTML & Javascript Magic! - Downloading Files Made Easy
# html # javascript #filedownload #webdevelopment #frontenddev #codingmagic ... 🔗 Downloading Files Made Easy: HTML & Javascript Magic! 💻✨.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found