All Projects → ZiadJ → Knockoutjs Reactor

ZiadJ / Knockoutjs Reactor

Licence: other
Recursively tracks changes within a view model no matter how deeply nested the observables are or whether they are nested within dynamically created array elements.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Knockoutjs Reactor

Executor
Watch for file changes and then execute command. Very nice for test driven development.
Stars: ✭ 14 (-81.82%)
Mutual labels:  watch
Saw
Fast, multi-purpose tool for AWS CloudWatch Logs
Stars: ✭ 1,071 (+1290.91%)
Mutual labels:  watch
Vue Builder Webpack Plugin
Webpack plugin to build vue files automatically
Stars: ✭ 70 (-9.09%)
Mutual labels:  watch
Npm Build Boilerplate
A collection of packages that build a website using npm scripts.
Stars: ✭ 963 (+1150.65%)
Mutual labels:  watch
Graphql Factory
A toolkit for building GraphQL
Stars: ✭ 44 (-42.86%)
Mutual labels:  subscription
Project Sauron
Tools to create a Native Windows Audit Collection Platform. Active Directory example provided
Stars: ✭ 58 (-24.68%)
Mutual labels:  subscription
In App Purchase
A Node.js module for in-App-Purchase for iOS, Android, Amazon and Windows.
Stars: ✭ 868 (+1027.27%)
Mutual labels:  subscription
Multiwatch
Simple task runner on directory changes that doesn't produce tons of logs if everything is OK 👌
Stars: ✭ 74 (-3.9%)
Mutual labels:  watch
Scroll Watcher
⚡️ 📜 A lightweight, blazing fast, rAF based, scroll watcher.
Stars: ✭ 51 (-33.77%)
Mutual labels:  watch
Twitter Webhook Boilerplate Node
A simple Node.js app using Express 4 for Twitter DMs and webhooks.
Stars: ✭ 69 (-10.39%)
Mutual labels:  subscription
Proxy Watcher
A library that recursively watches an object for mutations via Proxies and tells you which paths changed.
Stars: ✭ 35 (-54.55%)
Mutual labels:  watch
Automod Bot
Fun moderation economy bot discord.js
Stars: ✭ 41 (-46.75%)
Mutual labels:  watch
Djaoapp
User login, billing, access control as part of a session proxy
Stars: ✭ 61 (-20.78%)
Mutual labels:  subscription
Rate Ios
iOS Client of Rate Assistant - A rate search and subscription application.
Stars: ✭ 20 (-74.03%)
Mutual labels:  subscription
Pebble
Unofficial Pebble watch support for SailfishOS/Jolla
Stars: ✭ 71 (-7.79%)
Mutual labels:  watch
Iobroker.vis Timeandweather
ioBroker Widgets set with time and weather
Stars: ✭ 12 (-84.42%)
Mutual labels:  watch
Go Watch
监控你的程序文件变化并自动重启服务
Stars: ✭ 56 (-27.27%)
Mutual labels:  watch
Git Repo Watcher
A simple bash script to watch a git repository and pull upstream changes if needed.
Stars: ✭ 73 (-5.19%)
Mutual labels:  watch
Feedly Filtering And Sorting
Enhance the feedly website with advanced filtering and sorting capabilities
Stars: ✭ 73 (-5.19%)
Mutual labels:  subscription
Gaze
🔮 A globbing fs.watch wrapper built from the best parts of other fine watch libs.
Stars: ✭ 1,140 (+1380.52%)
Mutual labels:  watch

KO-Reactor

A KnockoutJS plugin that lets you track all changes within a view model seamlessly with the ability to pin point and process them on the fly. It does not require any modifications to the markup or view model itself which makes it ideal for testing and quick prototyping.

Usage:

ko.watch(targetObjectOrFunction, options, evaluatorCallback, context);

or

var property = ko.observable().watch(targetObjectOrFunction, options, evaluatorCallback, context);

targetObjectOrFunction accepts any subscribable or function/object containing the targeted subscribables.
options is only optional and can be replaced by evaluatorCallback the response and evaluation function.

Deep Watcher:
The depth option is used to limit the recursion depth. Its default value 1 limits it to a flat view model but a value of -1, as shown below, will fully unleash it:

var viewModel = { ... };
ko.watch(viewModel, { depth: -1 }, function(parents, child, item) {
	...
});

The callback function provides three arguments:

  1. parents: A list of all parents above the changed property.
  2. child: The child property that changed.
  3. item: Used to determine whether an array item has been added, moved or removed.

Note that for observable arrays, subscriptions are created or destroyed on the fly as new items are added or removed. To keep up with changes in the model structure itself however the mutable option needs to be set to true.

Auto Wrapper:
Setting the wrap option to true will make sure that all fields within the targeted object are wrapped within an observable even if new array items are added later on.

Chaining Support:
The chaining support provided adds in more ways to simplify the code and make it more readable. For example let's consider this simple view model:

var params = {
    p1 = ko.observable(),
    p2 = ko.observable(),
    p3 = ko.observable()
}

To update a variable, say items, whenever any parameter within params changes we would most probably write something along those lines:

var items = ko.observableArray();      	 	        var items = ko.computed(function() {
ko.computed = function() {             	    	        var p1 = self.params.p1();
    var p1 = self.params.p1();         	    	        var p2 = self.params.p2();
    var p2 = self.params.p2();         	OR	            var p3 = self.params.p3();
    var p3 = self.params.p3();         	         
														var newItems = ...;
    var newItems = ...;                     	        return newItems;
    self.items(newItems);               	        }
}                                       

However, using the plugin, we can just watch params right away like so and let it do the rest:

var items = ko.observableArray();         	    	var items = ko.observableArray();
ko.watch(params, function() {              		    items.watch(params, function() {    
    var newItems = ...;                 OR   	    	var newItems = ...;                 
    self.items(newItems);                   	        return newItems;                    
});                                       	      	}); 

Finally adding a bit of fluency to the mix we end up with the single block below:

var items = ko.observableArray().watch(params, function() {
    var newItems = ...;
    return newItems;    
});

Note that by omitting the target parameter we obtain a chainable version of .subscribe. So instead of creating a subscription separately like so:

var someProperty = ko.observable();
someProperty.subscribe(someFunction, options);

We can do away with the redundancy like so:

var someProperty = ko.observable().watch(someFunction, options);

Selective Subscription:
There are many ways we can go about making a selective watcher. Suppose we want to avoid watching the variable p3. To achieve this we could move p3 to another level like so:

var params = {
    p1: ko.observable(),
    p2: ko.observable(),
    ignored: {
        p3: ko.observable() 
    }
};

But this assumes that the depth option is set to 1. To avoid this we can pass in a new object made up of p1 and p2 only:

ko.watch({ 1: params.p1, 2: params.p2 }, function (parents, child, item) {
    ...
}

Or we can just use the hide option this way:

ko.watch(this.params, { hide: params.p3 }, function (parents, child, item) {
    ...
}

The easiest way however is to simply tag p3 as non-watchable like so:

var params = {
    p1: ko.observable(),
    p2: ko.observable(),
    p3: ko.observable().watch(false) 
};

For more advanced cases however we can make use of the beforeWatch option which gives us full control over the subscription process:

ko.watch(this.params, {
    beforeWatch: function (parents, child) {
        if (<some reason not to subscribe>)
            return false; // cancel subscription
    }
}, function (parents, child, item) {
	...
});

Pausable Listener:
Pausing and resuming a reactor on any property can be done like so:

this.data.watch(false);
//...do work
this.data.watch(true);

Dispose/Unwatch:
The watch function returns an object with a "dispose" method you can call to dispose the watch action:

var viewModel = { ... };
var res = ko.watch(viewModel, { depth: -1 }, function(parents, child, item) {
    ...
});

res.dispose();

Once disposed your model will be "unwatched"

Synchronous tracking: (since 1.4.0)
By default when new objects are added to the tree, they are automatically "watched" asynchronously (e.g: in a setTimeout) in order to keep the system more responsive.

Sometimes this behaviour is not "expected", so you can use the async: false option to force watch to happen "inline".

Single notification for multiple array changes vs change by change notifications (since 1.4.0)
By default when items are moved in an array you receive 2 different notifications, the first will report the "deleted item" and the second one will report the "added item".

If you prefer to receive an array of items in a single notification you can use the splitArrayChanges: false option. In that case you will receive an array of item instead of a single item even when there is only one item changed.

Projects using KO-Reactor:
As of now I'm only aware of this excellent undo manager by Stefano Bagnara:

https://github.com/bago/knockout-undomanager

Here's a Plunker showing it in action on an array within an array:

http://plnkr.co/edit/nB2129?p=preview

Reactor is also used (via Undomanager) in Mosaico the first opensource Email Template Editor:

https://github.com/voidlabs/mosaico

Do feel free to let me know if you have anything related to share and I'll gladly mention it here.

Further Notes:
Unlike ko.computed no listeners are created for subcribables within the evaluator function. So we no longer have to be concerned about creating unintended triggers as the code gets more complex.

Yet another usage not mentioned above example involves calling watch on a function as shown below:

ko.watch(function() { ... }, options);

However it is nothing more than a cosmetic enhancement since it only returns a computed of the function being passed in.

For an extensive list of available options please consult the param sections of the source code.

Development

In order to build and minify you can simply call grunt:

grunt

If you want a live rebuild for each changed

grunt develop

If you want to run the test suite:

grunt jasmine

If you want to generate the test runner in order to run the test suite in your browser

grunt jasmine:main:build
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].