3

State management: Two-way bindings and enhanced binding formatters

 2 years ago
source link: https://itnext.io/state-management-two-way-bindings-and-enhanced-binding-formatters-f0e9419b7c6b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

State management: Two-way bindings and enhanced binding formatters

The neo.mjs v2.0 release was focussed on the new view models implementation, which enables you to bind component configs to view model data properties anywhere inside the model hierarchy tree.

This article is covering the latest enhancements to make complex application based state management even easier and more powerful.

Content

  1. Introduction
  2. A real world use case
  3. Background infos
  4. Binding formatters based on Template Literals
  5. Two way bindings
  6. Formatters for booleans
  7. Formatters for numbers
  8. Formatters using methods
  9. Under the hood
  10. What is coming next?
  11. Final thoughts

1. Introduction

What are the key strengths of the neo.mjs Javascript UI framework?

  1. Obviously there is the “Application worker being the main actor” paradigm. Meaning: Your apps and components live within the App worker scope, which leaves the main thread mostly idle. The workers setup leads to a blazing fast performance and scalability. It recently got better using a MessageChannel for the App ← → Data workers communication (post messages no longer need to pass through main threads).
  2. The config system (a custom enhancement to the ES class system) makes state changes on component levels trivial (almost synchronous), so we don’t need hooks and can simply do more.
  3. The custom JSON based virtual DOM implementation allows any kind of complex changes at run time. This results in needing less component classes and the ability to create very complex widgets fairly easily. There are reasons why high level enterprise grade web components do not get created in Angular or React.
  4. View models and view controllers enable you to handle application (component tree) based state logic in a smart way and resolve many of the pain points the frontend development landscape is dealing with.

While you are mostly already aware of point one, I am not so sure if you already understand the meaning of the other points. Please correct me if I am wrong here.

After pushing the core and tooling side for quite a while (the new file buffer based SASS theming engine got super nice!), I decided to work on a “vertical” instead of pushing the more basic parts further.

For the v2.3 release the calendar implementation is the main focus, to show you the full power of what you can achieve with using the neo.mjs in the right way.

1. A real world use case

In case you have not seen the current state of the calendar implementation yet:

The calendar implementation supports different timezones, locales and is highly config driven: you can customise the widget in many ways.

The week, month and year views already support infinite scrolling and the week view drag and drop implementation is pretty close to the native macOS calendar.

Here is a short video to see it in action:

In case you would try to create a widget of this complexity with Angular or React, you would most likely end up with a huge amount of component based files. This is definitely not the case for neo.mjs:

1*UhZ0aRqGfWM6myN8kZxrIw.png?q=20
state-management-two-way-bindings-and-enhanced-binding-formatters-f0e9419b7c6b

So far I have been sticking to the “do not use view models for creating components” paradigm. I am making an exception for the calendar widget for two reasons:

  1. A calendar is more like an app than a component, so using a top level view model does make sense here. We need to pass way less configs down to child views. This approach will also enable you to use child views on their own. Example: You create an app and just want to use the calendar week view. This will be possible with just adding the view model to it.
  2. Education: The view model examples for the v2 release were pretty trivial. I think the best way to understand the benefits is a complex real world use case. Studying the code base can help you getting up to speed.

One extremely beautiful aspect of the calendar implementation is that non active views get removed from the real DOM, while keeping the JS component instances alive. We can change the state (configs) of inactive views any way we want, e.g. with using the settings sidebar. Changes will get added into the virtual dom locally → getting ignored from the vdom engine, until you activate the view again.

You can find the code base here:

Here is the online demo (Desktop for now).

dist/production
Minified webpack based build without source maps:
neo.mjs/dist/production/examples/calendar/basic/index.html

development mode (Chromium or Safari Tech Preview only)
Running the real JS code as it is directly inside your browser, no source maps needed:
neo.mjs/examples/calendar/basic/index.html

1*aiDPVdbD_liJv2urJPO9Rg.png?q=20
state-management-two-way-bindings-and-enhanced-binding-formatters-f0e9419b7c6b

As you can see, it does live within the App worker.

3. Background infos

In case you want to get more infos on the v2 release in general or more specifically on the view models implementation, I strongly recommend to dive into the blog:

https://neomjs.github.io/pages/

Here are some relevant direct links:

4. Binding formatters based on Template Literals

Since especially Angular and React devs love using templates for whatever reason, binding formatters based on Template Literals are available.

Examples:

  1. You can bind to any component config.
  2. You can use multiple data properties inside your formatters.
  3. You can use data properties inside the full component tree view model hierarchy, even different model data props inside one formatter.
  4. You can create nested data structures. All leave nodes will trigger change events.

5. Two way bindings

While we had the support to automatically update component configs whenever data properties which are used inside your formatters change, the other direction was missing.

We can reduce a lot of boiler-plate code, in case changing a component config can as well automatically update the bound model data property.

You can now do this:

Instead of assigning an arrow function directly to a component config, you can assign a config object. We need the property towWay: true to let the engine know that it should update model data properties as well.

We are using the value property to assign our formatter.

It is important to know that this can only work for 1:1 bindings for component configs to data properties. Reverting any kind of complex formatters can not work in a generic way.

If you want to use complex formatters, you can however use the afterSet() config methods and manually update your related view model data properties.

6. Formatters for booleans

For the first binding formatters implementation, all arrow functions had to use template literals → ``.

While working on the calendar I realised that this is a problem, since binding to boolean data props returned strings.

The new version also supports arrow functions without ``, as you have just seen inside the two way binding examples.

For booleans, you can now use bindings like this:

bind: {
value: data => data.foo || data.bar && data.nested.baz
}

7. Formatters for numbers

Similar to booleans, you can also get numbers back directly:

bind: {
value: data => data.foo + data.bar * data.nested.baz
}

8. Formatters using methods

The most impressive addition is that you can now easily use method as well:

bind: {
value: data => DateUtil.convertToyyyymmdd(data.currentDate)
}

9. Under the hood

The support for two way bindings was a quick win.

src/Neo.mjs#L511

The generic config setter now triggers an afterSetConfig() method in case it does exists for all configs, right after the named afterSet() method for a single config.

Not all classes in neo need to extend Component. I can not repeat this one often enough (e.g. controllers, data stores, selection models can just extend core.Base).

The lowest entry point for model.Component is obviously component.Base though, so I added the new method here:

Line 14 is helpful, since you can manually update model data properties in the same way.

The support for methods inside binding arrow functions was way more tricky.

While it was fairly easy inside the development mode for:

data => DateUtil.convertToyyyymmdd(data.currentDate)

the dist/production output minified it to:

e=>s.Z.convertToyyyymmdd(e.currentDate)

The component model regexes to extract model related data properties were not up for the challenge, since we can no longer rely on the fact that only “data” will get shortened to a one character variable.

The related view model code:

For dist/production we do need a dynamic regex to resolve this. The new solutions works very well.

9. What is coming next?

As mentioned earlier, for the v2.3 release the calendar widget is the main focus.

I will create another article shortly to talk more about the neo roadmap in general. The amount of items (epics) is huge.

I received quite a lot of requests for a buffered grid implementation, which should support infinite scrolling for columns and rows.

I think it would take me around 3 months to create a blazing fast implementation, which can compete with solutions like ag grid from a performance perspective (obviously not with the full amount of features at first).

10. Final thoughts

You can find the neo project here:

You are very welcome to join the project slack channel for questions and feedback:

What are the problems the neo project is dealing with?

I got the technical side of things covered. The project is literally getting better every day I work on it and I push the code base a lot.

Getting more contributors would be appreciated. Unless you consider yourself to belong to the top 1% of Javascript devs, helping on the core or very advanced widgets is not an option to get started with.

However, there are plenty of “easy” basic widgets that can use more polishing.

You can also write articles on how to get started or create easy demo apps. This will buy me more time to focus on the challenging parts.

The real problem the project is dealing with is the business development side.

After putting in 3 years of my full and unpaid working time (more than 10,000 commits inside the ecosystem), I am no longer able to keep pushing it full time.

So far, neo has one sponsor, but $100 / month does not cover my fixed living costs.

I could use a partner here. Getting shares is an option in case this works out fine.

If more sponsors support the project, I can continue pushing it like crazy and you can expect more incredible results, which will provide a lot of value for your frontend development.

In case this does not happen, I have no choice other than switching to a “freemium” business model. No worries, the code base as it is will stay fully open sourced (MIT licensed).

However, after finishing the basic versions of the calendar and buffered grid, there would be premium versions including more features. E.g. for the calendar: event collisions, multi day events, advanced drag&drop for multi day events. For the grid: pro features like grouping.

I would love to keep everything open source, but making this possible relies on getting more support from the industry. It is up to you!

Best regards & happy coding,
Tobias


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK