// This is a prototype for a Chiasm plugin that does data binding between Chiasm // components. It uses a special domain specific language (DSL) to express two // types of data binding links between two components: // // * Unidirectional `myComponent.myPropertyA -> myOtherComponent.myPropertyB` // * Bidirectional (planned, not implemented) `myComponent.myPropertyA <-> myOtherComponent.myPropertyB` function Links(chiasm) { var model = Model({ publicProperties: [ "bindings" ], bindings: [] }); var sourceListeners = []; model.when("bindings", function (bindings){ var oldSourceListeners = sourceListeners; sourceListeners = []; // Clear out the listeners for the old bindings. oldSourceListeners.forEach(function (_){ chiasm.getComponent(_.sourceAlias).then(function (sourceComponent){ sourceComponent.cancel(_.listener); }); }); // Add listeners for the new bindings. bindings.forEach(function(bindingExpr){ // Parse the binding expression of the form // "sourceAlias.sourceProperty -> targetAlias.targetProperty" var parts = bindingExpr.split("->").map(function(str){ return str.trim(); }), source = parts[0].split("."), sourceAlias = source[0], sourceProperty = source[1], target = parts[1].split("."), targetAlias = target[0], targetProperty = target[1]; // Retreive the source and target components. chiasm.getComponent(sourceAlias).then(function(sourceComponent){ chiasm.getComponent(targetAlias).then(function(targetComponent){ // TODO report errors for missing components. // Add a reactive function that binds the source to the target. var listener = sourceComponent.when(sourceProperty, function(value){ targetComponent[targetProperty] = value; }); // Keep track of the added listener so it can be removed later. sourceListeners.push({ sourceAlias: sourceAlias, listener: listener }); }); }); }); }); return model; }