JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.0/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="Ctrl1">
<input type="text" ng-model="firstName"/>
<input type="text" ng-model="lastName"/>
<ul>
<li>{{firstName}}</li>
<li>{{lastName}}</li>
</ul>
</div>
<div ng-controller="Ctrl2">
<input type="text" ng-model="firstName"/>
<input type="text" ng-model="lastName"/>
<ul>
<li>{{firstName}}</li>
<li>{{lastName}}</li>
</ul>
</div>
</div>
JavaScript
angular.module('Scope.safeApply', []).run(function($rootScope) {
$rootScope.$safeApply = function() {
var $scope, fn, force = false;
if(arguments.length == 1) {
var arg = arguments[0];
if(typeof arg == 'function') {
fn = arg;
}
else {
$scope = arg;
}
}
else {
$scope = arguments[0];
fn = arguments[1];
if(arguments.length == 3) {
force = !!arguments[2];
}
}
$scope = $scope || this;
fn = fn || function() { };
if(force || !$scope.$$phase) {
$scope.$apply ? $scope.$apply(fn) : $scope.apply(fn);
}
else {
fn();
}
};
});
var knockoutBind = function(scope, name, knockoutObservable){
scope.$watch(name, function(n, o) { knockoutObservable(n);});
knockoutObservable.subscribe(function(n) {
scope.$safeApply(function() {
scope[name] = n;
});
});
};
var app = angular.module('app', ['Scope.safeApply']);
app.controller('Ctrl1', function ($scope, userContext)
{
$scope.firstName = userContext.firstName();
$scope.lastName = userContext.lastName();
knockoutBind($scope,"firstName", userContext.firstName);
knockoutBind($scope,"lastName", userContext.lastName);
});
app.controller('Ctrl2', function($scope, userContext)
{
$scope.firstName = userContext.firstName();
$scope.lastName = userContext.lastName();
knockoutBind($scope,"firstName", userContext.firstName);
knockoutBind($scope,"lastName", userContext.lastName);
});
var userDataContext = {
firstName: ko.observable("John"),
lastName: ko.observable("Doe")
};
app.value('userContext', userDataContext);
setTimeout(function() {
console.log("change firstname");
userDataContext.firstName("Bart");
}, 3000);