UNPKG

@danielkalen/simplybind

Version:

Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.

1,530 lines (1,117 loc) 105 kB
mocha.setup('bdd') expect = chai.expect should = chai.should() describe "SimplyBind", ()-> before ()-> startSandbox() window.server = sinon.fakeServer.create() server.respondWith '/local', '' server.respondWith '/get/some/data.json', [ 200 { 'Content-Type': 'application/json' } JSON.stringify('prop': 'externalValues': 'it works :)') ] server.respondWith '/get/some/data2.json', [ 200 { 'Content-Type': 'application/json' } JSON.stringify('prop': 'externalValues': 'it works :)') ] server.respondWith '/get/nonexistent', '' server.respondWith '/set/some/data.json', [ 200 { 'Content-Type': 'application/json' } JSON.stringify('prop': 'externalValues': 'it works too :)') ] server.respondWith '/set/some/data2.json', [ 200 { 'Content-Type': 'application/json' } JSON.stringify('prop': 'externalValues': 'it works too :)') ] server.autoRespond = true server.autoRespondAfter = 0 it "should return an options list when calling SimplyBind.options", ()-> options = SimplyBind.options expect(options.silent).not.to.be.undefined expect(options.placeholderStart).not.to.be.undefined expect(options.placeholderEnd).not.to.be.undefined expect(options.liveProps).not.to.be.undefined expect(options.ignoreCase).not.to.be.undefined expect(options.dispatchEvents).not.to.be.undefined expect(options.updateEvenIfUndefined).not.to.be.undefined expect(options.updateEvenIfSame).not.to.be.undefined expect(options.mutateInherited).not.to.be.undefined expect(options.mutateArrayMethods).not.to.be.undefined expect(options.invokeOnBind).not.to.be.undefined it "should set a new value for a single option when calling SimplyBind.setOption()", ()-> expect(SimplyBind.options.silent).to.equal false SimplyBind.setOption 'silent', true expect(SimplyBind.options.silent).to.equal true SimplyBind.setOption 'silent', false it "should set new values for a all the options passed when calling SimplyBind.setOptions()", ()-> expect(SimplyBind.options.silent).to.equal false expect(SimplyBind.options.liveProps).to.equal true SimplyBind.setOptions 'silent': true 'liveProps': false expect(SimplyBind.options.silent).to.equal true expect(SimplyBind.options.liveProps).to.equal false SimplyBind.setOptions 'silent': false 'liveProps': true SimplyBind.setOptions {} expect(SimplyBind.options.silent).to.equal false expect(SimplyBind.options.liveProps).to.equal true it "should not add non-existing options when they are added via .setOptions", ()-> SimplyBind.setOptions placeholderStart: '{{' placeholderEnd: '}}' youtube: 'yea!' expect(SimplyBind.options.placeholderStart).to.equal '{{' expect(SimplyBind.options.placeholderEnd).to.equal '}}' expect(SimplyBind.options.youtube).to.be.undefined it 'should apply input-simplybind polyfill', (done)-> $inputA.one 'input-simplybind', ()-> expect(true).to.equal true done() $inputA.trigger 'input-simplybind' it "should only accept a param value with the constructor of String, Number, Function, or SimplyBounded", ()-> symbol = ()-> SimplyBind Symbol('5') expect(symbol).to.throw() it "should only accept a param value with the constructor of String or SimplyBounded that isn't empty", ()-> emptyString = ()-> SimplyBind '' numberZero = ()-> SimplyBind 0 expect(emptyString).to.throw() expect(numberZero).not.to.throw() it "should not accept null subjects in .of()", ()-> fn = ()-> SimplyBind('prop').of null expect(fn).to.throw() it "should not accept undefined subjects in .of()", ()-> fn = ()-> SimplyBind('prop').of undefined expect(fn).to.throw() it "should not accept string, number, or boolean subjects in .of()", ()-> fn = ()-> SimplyBind('prop').of 'string' fn2 = ()-> SimplyBind('prop').of 3 fn3 = ()-> SimplyBind('prop').of true expect(fn).to.throw() expect(fn2).to.throw() expect(fn3).to.throw() it "should not accept non-object subjects in .of()", ()-> fn = ()-> SimplyBind('prop').of Symbol('test') expect(fn).to.throw() it "should throw a warning when binding a property of a jQuery element with multiple els", ()-> origLog = console.log console.log = chai.spy() SimplyBind('value').of $('input[type="text"]') expect(console.log).to.have.been.called() console.log = origLog it "should throw a warning when binding a property of an empty NodeList/HTMLCollection", ()-> origLog = console.log console.log = chai.spy() SimplyBind('value').of document.querySelectorAll('nonexistent') expect(console.log).to.have.been.called() SimplyBind('value').of document.getElementsByTagName('nonexistent') expect(console.log).to.have.been.called() console.log = origLog it "should throw a warning when binding a property of an empty jQuery element", ()-> origLog = console.log console.log = chai.spy() SimplyBind('value').of $('input[type="nonexistent"]') expect(console.log).to.have.been.called() console.log = origLog it "should throw a warning when creating a binding with a non-function object using the .transform or .transformAll method.", ()-> origLog = console.log console.log = chai.spy() SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transform [] expect(console.log).to.have.been.called() SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transformAll [] expect(console.log).to.have.been.called() console.log = origLog restartSandbox() it "should\'t throw warnings if errors are suppressed, but should throw errors regardless", ()-> emptyString = ()-> SimplyBind '' SimplyBind.setOption 'silent', true origLog = console.log console.log = chai.spy() SimplyBind('value').of $('input[type="text"]') expect(console.log).not.to.have.been.called() expect(emptyString).to.throw() console.log = origLog SimplyBind.setOption 'silent', false describe "Bound Object", ()-> before ()-> restartSandbox() it "should have the proper methods depending on its stage", ()-> bound = ()-> SimplyBind '1' expect(()-> bound().of objectA).not.to.throw() expect(()-> bound().ofEvent objectA).not.to.throw() expect(()-> bound().ofExternal '/local').not.to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').to.throw() expect(()-> bound().get()).to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').of objectA expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').not.to.throw() expect(()-> bound().toExternal '/local').not.to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').ofEvent 'click' expect(()-> bound().of objectA).not.to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').to.throw() expect(()-> bound().get()).to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').ofEvent('click').of inputA expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').not.to.throw() expect(()-> bound().toExternal '/local').not.to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').of(objectA).to 'prop1' expect(()-> bound().of objectA).not.to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').to.throw() expect(()-> bound().get()).to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of objectB expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).not.to.throw() expect(()-> bound().transformAll ()->).not.to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).and 'prop2' expect(()-> bound().of objectA).not.to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').to.throw() expect(()-> bound().get()).to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).to.throw() expect(()-> bound().unBind()).to.throw() expect(()-> bound().chainTo ()->).to.throw() expect(()-> bound().updateDepsOnEvent 'a').to.throw() expect(()-> bound().removeEvent 'a').to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).and('prop2').of objectB expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).not.to.throw() expect(()-> bound().transformAll ()->).not.to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).bothWays() expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).not.to.throw() expect(()-> bound().transformAll ()->).not.to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).transform ()-> expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).transformAll ()-> expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).to.throw() expect(()-> bound().transformAll ()->).to.throw() expect(()-> bound().bothWays()).to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()-> ).and ()-> expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).not.to.throw() expect(()-> bound().transformAll ()->).not.to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() bound = ()-> SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()-> ).and(()-> ).chainTo ()-> expect(()-> bound().of objectA).to.throw() expect(()-> bound().ofEvent objectA).to.throw() expect(()-> bound().ofExternal '/local').to.throw() expect(()-> bound().to 'prop2').to.throw() expect(()-> bound().toExternal '/local').to.throw() expect(()-> bound().and 'prop2').not.to.throw() expect(()-> bound().set 'value').not.to.throw() expect(()-> bound().get()).not.to.throw() expect(()-> bound().transform ()->).not.to.throw() expect(()-> bound().transformAll ()->).not.to.throw() expect(()-> bound().bothWays()).not.to.throw() expect(()-> bound().stopPolling()).to.throw() expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw() expect(()-> bound().unBind()).not.to.throw() expect(()-> bound().chainTo ()->).not.to.throw() expect(()-> bound().updateDepsOnEvent 'a').not.to.throw() expect(()-> bound().removeEvent 'a').not.to.throw() it "should have the correct public properties", ()-> bound = SimplyBind('prop1').of(objectA).to('prop2').of(objectB) expect(bound.ID).not.to.be.undefined expect(typeof bound.has).to.equal 'object' expect(bound.has.initBind).not.to.be.undefined expect(bound.has.tf).not.to.be.undefined expect(bound.has.massTf).not.to.be.undefined expect(bound.has.event).not.to.be.undefined expect(bound.has.interval).not.to.be.undefined expect(bound.value).not.to.be.undefined expect(bound.stage).not.to.be.undefined expect(bound.original).not.to.be.undefined expect(bound.dependents).not.to.be.undefined expect(bound._).not.to.be.undefined it "should return the same SimplyBounded object from cache if in it", ()-> bound1 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB) bound2 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB) expect(bound1.ID).to.equal bound2.ID it "should accept number attributes", ()-> tempObject = '1': 'text' '2': 'shmext' SimplyBind(1).of(tempObject).to(2).of tempObject expect(tempObject[1]).to.equal 'text' expect(tempObject[2]).to.equal 'text' it "should create the passed property on the parent object if undefined", ()-> bound = SimplyBind('prop20').of(objectA).to('prop20').of(objectB) expect(objectA.prop20).not.to.be.undefined expect(objectB.prop20).not.to.be.undefined expect(objectA.prop20).to.be.null expect(objectB.prop20).to.be.null bound.set 'new value' expect(objectA.prop20).to.equal 'new value' expect(objectB.prop20).to.equal 'new value' it "should return the appropriate values when using .value prop and .get() method", ()-> tempObject = 'a': 'with' 'b': 'text {{verb}} a placeholder' SimplyBind('a').of(tempObject).to('b.verb').of tempObject bound = SimplyBind('b.verb').of(tempObject) expect(tempObject.b).to.equal 'text with a placeholder' expect(bound.value).to.equal 'text with a placeholder' expect(bound.get()).to.equal 'with' tempObject.a = 'without' expect(tempObject.b).to.equal 'text without a placeholder' expect(bound.value).to.equal 'text without a placeholder' expect(bound.get()).to.equal 'without' describe "Data Binding", ()-> before ()-> restartSandbox() describe "Misc.", ()-> it "can make inherited properties live properties if so set in options, otherwise it shouldn\'t", ()-> testArray = [] SimplyBind.setOption 'mutateInherited', true Array::inherited = 'Hello :)' SimplyBind('inherited').of(testArray).to('prop1').of objectB testArray.inherited = 'inherited live prop change :)' expect(objectB.prop1).to.equal 'inherited live prop change :)' delete Array::inherited SimplyBind.setOption 'mutateInherited', false Array::inherited2 = 'Hello :)' SimplyBind('inherited2').of(testArray).to('prop2').of objectB testArray.inherited2 = 'inherited prop shouldn\'t change' expect(objectB.prop2).not.to.equal 'inherited prop shouldn\'t change' delete Array::inherited2 SimplyBind.setOption 'mutateInherited', false it "should invoke the original descriptor\'s setter and getter on a live property (if exists)", ()-> prop7 = 'hey!' invokeCountGet = 0 invokeCountSet = 0 Object.defineProperty objectA, 'prop7', enumerable: true configurable: true get: ()-> invokeCountGet++ prop7 set: (val)-> invokeCountSet++ prop7 = val expect(objectA.prop7).to.equal 'hey!' expect(invokeCountGet).to.equal 1 expect(invokeCountSet).to.equal 0 SimplyBind('prop7').of(objectA).to('prop3').of objectB objectA.prop7 = 'hello!' expect(invokeCountGet).to.equal 2 expect(invokeCountSet).to.equal 1 expect(objectA.prop7).to.equal 'hello!' objectA.prop7 = 'hi!' expect(invokeCountGet).to.equal 3 expect(invokeCountSet).to.equal 2 it "shouldn\'t change anything if passed a null/undefined value to .to()", ()-> restartSandbox() bound = SimplyBind('prop1').of(objectA).to(null) expect(bound.stage).to.equal 1 bound = SimplyBind('prop1').of(objectA).to(undefined) expect(bound.stage).to.equal 1 if typeof Symbol != 'undefined' symbol = ()-> SimplyBind('prop1').of(objectA).to Symbol('whatever') expect(symbol).to.throw() it "shouldn\'t change anything if passed a null/undefined value to .and()", ()-> restartSandbox() bound = SimplyBind('prop1').of(objectA).to(()->).and(null) expect(bound.stage).to.equal 3 bound = SimplyBind('prop1').of(objectA).to(()->).and(undefined) expect(bound.stage).to.equal 3 it "can accept a SimplyBounded object as an argument for .of()", ()-> bound = SimplyBind('prop3').of(objectA).to('prop3').of(objectB) bound.set 'standard' expect(objectA.prop3).to.equal 'standard' expect(objectB.prop3).to.equal 'standard' bound2 = SimplyBind('prop4').of(bound).to('prop4').of(objectB) bound2.set 'ofBounded' expect(objectA.prop4).to.equal 'ofBounded' expect(objectB.prop4).to.equal 'ofBounded' it "should update values and dependents even if it\'s unchanged, if set the updateEvenIfSame option to true", ()-> invokeCount = 0 objectA.prop6 = 'start' objectB.prop6 = '' binding = SimplyBind('prop6').of(objectA).to('prop6').of(objectB).transform (value)-> invokeCount++; return value expect(objectB.prop6).to.equal 'start' expect(invokeCount).to.equal 1 objectA.prop6 = 'shouldn\'t update' expect(objectB.prop6).to.equal 'shouldn\'t update' expect(invokeCount).to.equal 2 objectA.prop6 = 'shouldn\'t update' expect(objectB.prop6).to.equal 'shouldn\'t update' expect(invokeCount).to.equal 2 objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' expect(invokeCount).to.equal 2 binding.setOption 'updateEvenIfSame', true objectA.prop6 = 'should update' expect(objectB.prop6).to.equal 'should update' expect(invokeCount).to.equal 3 objectA.prop6 = 'should update' objectA.prop6 = 'should update' objectA.prop6 = 'should update' objectA.prop6 = 'should update' expect(invokeCount).to.equal 7 binding.setOption 'updateEvenIfSame', false objectA.prop6 = 'shouldn\'t update' expect(objectB.prop6).to.equal 'shouldn\'t update' expect(invokeCount).to.equal 8 objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' objectA.prop6 = 'shouldn\'t update' expect(invokeCount).to.equal 8 it "can handle complex chainings using the .chainTo() method", ()-> outerstate = 'first': null 'second': null 'third': null objectA.prop1 = 'Hello World' SimplyBind('prop1').of(objectA) .to('prop1').of(objectB) .and('prop2').of(objectA) .and (val)-> outerstate.first = val .transformAll (val)-> val.toUpperCase() .chainTo('prop2').of(objectB) .and('prop3').of(objectA) .transform (val)-> val.toLowerCase() .chainTo('prop3').of(objectB) .and('prop4').of(objectA) .and (val)-> outerstate.second = val .chainTo('prop4').of(objectB) .and (val)-> outerstate.third = val.slice(0, 5) expect(outerstate.first).to.equal 'HELLO WORLD' expect(outerstate.second).to.equal 'hello world' expect(outerstate.third).to.equal 'hello' expect(objectA.prop1).to.equal 'Hello World' expect(objectA.prop2).to.equal 'HELLO WORLD' expect(objectB.prop1).to.equal 'HELLO WORLD' expect(objectB.prop2).to.equal 'HELLO WORLD' expect(objectA.prop3).to.equal 'hello world' expect(objectB.prop3).to.equal 'hello world' expect(objectA.prop4).to.equal 'hello world' expect(objectB.prop4).to.equal 'hello world' it "should update dependents even if the new value is undefined, if so set in the options", ()-> restartSandbox() binding = SimplyBind('prop1').of(objectA).to('prop1').of(objectB) objectA.prop1 = 10 expect(objectB.prop1).to.equal 10 objectA.prop1 = window.nonexistent # undefined value expect(objectB.prop1).to.equal 10 binding.setOption 'updateEvenIfUndefined', true objectA.prop1 = 20 expect(objectB.prop1).to.equal 20 objectA.prop1 = window.nonexistent # undefined value expect(objectB.prop1).to.be.undefined binding.setOption 'updateEvenIfUndefined', false it "dependents should update their subdependents when being updated by an independent, even if these dependents are not liveProps", ()-> objectA.prop2 = 0.8 SimplyBind('prop2').of(objectA) .to('opacity').of regA.style SimplyBind('opacity').of(regA.style) .to('font-size').of(regA.style) .transform (opacity)-> opacity * 20 + 'px' .and('font-size').of(regB.style) .transform (opacity)-> opacity * 40 + 'px' expect(regA.style.opacity.toString()).to.equal '0.8' expect(regA.style['font-size']).to.equal '16px' expect(regB.style['font-size']).to.equal '32px' objectA.prop2 = 0.5 expect(regA.style.opacity.toString()).to.equal '0.5' expect(regA.style['font-size']).to.equal '10px' expect(regB.style['font-size']).to.equal '20px' describe "Polling values in an interval", ()-> it 'can manually poll the subject at a given interval via the .pollEvery method', (done)-> shouldFinish = false lastValue = undefined bound = undefined arr = [] fn = (length)-> if shouldFinish expect(length).to.equal 2 bound.stopPolling() done() else lastValue = length bound = SimplyBind('length').of(arr).to(fn) expect(lastValue).to.equal 0 arr.push 'some value' arr.push 'and another' expect(lastValue).to.equal 0 arr = [] bound = SimplyBind('length').of(arr).to(fn).pollEvery(5) setTimeout ()-> shouldFinish = true expect(lastValue).to.equal 0 arr.push 'some value' arr.push 'and another' expect(lastValue).to.equal 0 , 8 it 'can manually poll the subject at a given interval via the .pollEvery method, even if it\'s an Attr type', (done)-> shouldFinish = false lastValue = undefined bound = undefined h1 = regAH1 fn = (value)-> if shouldFinish expect(value).to.equal 'and another' bound.stopPolling() done() else lastValue = value bound = SimplyBind('attr:data-attr').of(h1).to(fn).pollEvery(5) bound.set 'initial value' setTimeout ()-> shouldFinish = true expect(lastValue).to.equal 'initial value' h1.setAttribute 'data-attr', 'some value' h1.setAttribute 'data-attr', 'and another' expect(lastValue).to.equal 'initial value' , 8 it 'can manually poll the subject and invoke it if it\'s a function at a given interval via the .pollEvery method', (done)-> shouldFinish = false timesCalled = 0 bound = undefined sourceFn = ()-> timesCalled++ fn = (length)-> if shouldFinish expect(timesCalled).to.equal 9 bound.stopPolling() done() else if timesCalled > 5 shouldFinish = true bound = SimplyBind(sourceFn).to(fn).pollEvery(5) expect(timesCalled).to.equal 1 describe "Objects (Standard)", ()-> it "supports live properties", ()-> restartSandbox() SimplyBind('prop1').of(objectA).to('prop1').of objectB objectA.prop1 = 'live prop change :)' expect(objectB.prop1).to.equal 'live prop change :)' it "should avoid infinite loops", ()-> SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays() SimplyBind('prop1').of(objectB).to('prop1').of(objectC).bothWays() SimplyBind('prop1').of(objectC).to('prop1').of(objectA).bothWays() objectA.prop1 = 'objectA' expect(objectB.prop1).to.equal 'objectA' expect(objectC.prop1).to.equal 'objectA' objectB.prop1 = 'objectB' expect(objectA.prop1).to.equal 'objectB' expect(objectC.prop1).to.equal 'objectB' it "can bind an object\'s property to another\'s", ()-> restartSandbox() bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB) bound.set 'changed' expect(objectB.prop1).to.equal 'changed' it "can bind an functions\' property to another\'s", ()-> fn = ()-> fn.prop = 'some value' bound = SimplyBind('prop').of(fn).to('prop1').of(objectB) bound.set 'changed' expect(objectB.prop1).to.equal 'changed' it "can match case in property names (unless told otherwise via options.ignoreCase)", ()-> restartSandbox() bound = SimplyBind('PrOp1').of(objectA).to('prOP1').of(objectB) bound.set 'not changed' expect(objectB.prop1).not.to.equal 'not changed' SimplyBind.setOption 'ignoreCase', true bound = SimplyBind('PrOp2').of(objectA).to('prOP2').of(objectB) bound.set 'changed' expect(objectB.prop2).to.equal 'changed' SimplyBind.setOption 'ignoreCase', false it "can bind even if the value is falsy", ()-> restartSandbox() bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB) bound.set '' expect(objectB.prop1).to.equal '' bound.set 0 expect(objectB.prop1).to.equal 0 bound.set false expect(objectB.prop1).to.equal false bound.set undefined expect(objectB.prop1).to.equal false it "can bind an object\'s property to multiple other properties", ()-> restartSandbox() SimplyBind('prop1').of(objectA) .to('prop1').of(objectB) .and('prop2').of(objectB) .and('prop3').of(objectB) .and('prop4').of(objectB) objectA.prop1 = 'all at once' expect(objectB.prop1).to.equal 'all at once' expect(objectB.prop2).to.equal 'all at once' expect(objectB.prop3).to.equal 'all at once' expect(objectB.prop4).to.equal 'all at once' it "can bind two objects\' properties both ways", ()-> restartSandbox() SimplyBind('prop2').of(objectA).to('prop2').of(objectB).bothWays() objectA.prop2 = 'changed from objectA' expect(objectB.prop2).to.equal 'changed from objectA' objectB.prop2 = 'changed from objectB' expect(objectA.prop2).to.equal 'changed from objectB' it "can bind multiple bindings and apply the .bothWays() method only to the last binding.", ()-> restartSandbox() SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).and('prop3').of(objectB).bothWays().and('prop4').of objectB objectA.prop1 = 'all at once' expect(objectB.prop1).to.equal 'all at once' expect(objectB.prop2).to.equal 'all at once' expect(objectB.prop3).to.equal 'all at once' expect(objectB.prop4).to.equal 'all at once' objectB.prop1 = 'almost all as well since objectA.prop1 gets updated and updates all of its decendents' expect(objectA.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents' expect(objectB.prop2).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents' expect(objectB.prop3).to.equal 'all at once' expect(objectB.prop4).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents' objectB.prop3 = 'just a few' expect(objectA.prop1).to.equal 'just a few' expect(objectB.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents' expect(objectB.prop2).to.equal 'just a few' expect(objectB.prop4).to.equal 'just a few' it "can unbind all bindings", ()-> restartSandbox() modified = false bound = SimplyBind('prop1').of(objectA) .to('prop1').of(objectB).bothWays() .and('prop2').of(objectB).bothWays() .and('prop1').of(objectC).bothWays() .and('prop2').of(objectC).bothWays() .and('value').of(textarea).bothWays() .and ()-> modified = true expect(objectB.prop1).to.equal 'some string' expect(objectB.prop2).to.equal 'some string' expect(objectC.prop1).to.equal 'some string' expect(objectC.prop2).to.equal 'some string' expect(textarea.value).to.equal 'some string' expect(modified).to.equal true modified = false bound.unBind() objectA.prop1 = 'should change' expect(modified).to.equal false expect(objectB.prop1).to.equal 'should change' expect(objectB.prop2).to.equal 'should change' expect(objectC.prop1).to.equal 'should change' expect(objectC.prop2).to.equal 'should change' expect(textarea.value).to.equal 'should change' SimplyBind.unBindAll objectA objectA.prop1 = 'shouldn\'t change' expect(objectB.prop1).to.equal 'should change' expect(objectB.prop2).to.equal 'should change' expect(objectC.prop1).to.equal 'should change' expect(objectC.prop2).to.equal 'should change' expect(textarea.value).to.equal 'should change' describe "Placeholders", ()-> it "can bind an object\'s property to another\'s with a placeholder", ()-> restartSandbox() objectB.prop1 = 'The size of this shirt is {{size}}, man!' bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB) bound.set 'Medium' expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!' it "shouldn\'t perform any changes if trying to update a placeholder that doesn\'t exist", ()-> restartSandbox() objectB.prop1 = 'The size of this shirt is _____, man!' bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB) bound.set 'Medium' expect(objectB.prop1).to.equal 'The size of this shirt is _____, man!' it "can bind even if the value is not a string", ()-> restartSandbox() objectB.prop1 = 'The size of this shirt is {{size}}, man!' bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB) bound.set false expect(objectB.prop1).to.equal 'The size of this shirt is false, man!' bound.set null expect(objectB.prop1).to.equal 'The size of this shirt is null, man!' bound.set {} expect(objectB.prop1).to.equal 'The size of this shirt is [object Object], man!' it "can bind even when the selector has extra dot-notations", ()-> restartSandbox() objectB.prop1 = 'The size of this shirt is {{size.tedious}}, man!' bound = SimplyBind('prop1').of(objectA).to('prop1.size.tedious').of(objectB) bound.set 'Medium' expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!' it "can bind with a custom placeholder", ()-> restartSandbox() SimplyBind.setOption 'placeholderStart', '^^' SimplyBind.setOption 'placeholderEnd', '$$' $inputA.val 'The size of this shirt is ^^size$$, man!' bound = SimplyBind('prop1').of(objectA).to('value.size').of(inputA) bound.set 'XXS' expect($inputA.val()).to.equal 'The size of this shirt is XXS, man!' SimplyBind.setOption 'placeholderStart', '{{' SimplyBind.setOption 'placeholderEnd', '}}' it "can bind multiple values to a string that has multiple placeholders", ()-> restartSandbox() objectA.prop1 = 'The following text is {{verb}} {{nounOne}} and {{nounTwo}}' sampleObject = 'verb': 'not' 'nounOne': 'small' 'nounTwo': 'pretty' SimplyBind('verb').of(sampleObject).to('prop1.verb').of objectA SimplyBind('nounOne').of(sampleObject).to('prop1.nounOne').of objectA SimplyBind('nounTwo').of(sampleObject).to('prop1.nounTwo').of objectA expect(objectA.prop1).to.equal 'The following text is not small and pretty' sampleObject.verb = 'very' sampleObject.nounOne = 'big' sampleObject.nounTwo = 'ugly' expect(objectA.prop1).to.equal 'The following text is very big and ugly' sampleObject.verb = 'not' sampleObject.nounOne = 'small' sampleObject.nounTwo = 'pretty' expect(objectA.prop1).to.equal 'The following text is not small and pretty' it "can bind multiple values to a string that has multiple placeholders + transforms", ()-> restartSandbox() objectA.prop1 = 'The following text is {{verbOne}} ({{verbTwo}}) {{nounOne}} and {{nounTwo}}' caseMethod = 'toUpperCase' sampleObject = 'verb': 'not' 'nounOne': 'small' 'nounTwo': 'pretty' SimplyBind('verb').of(sampleObject) .to('prop1.verbOne').of(objectA).transform (value)-> value[caseMethod]() SimplyBind('verb').of(sampleObject) .to('prop1.verbTwo').of(objectA).transform (value)-> value.toLowerCase() SimplyBind('nounOne').of(sampleObject) .to('prop1.nounOne').of(objectA).transform (value)-> value[caseMethod]() SimplyBind('nounTwo').of(sampleObject) .to('prop1.nounTwo').of(objectA).transform (value)-> value[caseMethod]() expect(objectA.prop1).to.equal 'The following text is NOT (not) SMALL and PRETTY' sampleObject.verb = 'Very' sampleObject.nounOne = 'Big' sampleObject.nounTwo = 'Ugly' expect(objectA.prop1).to.equal 'The following text is VERY (very) BIG and UGLY' caseMethod = 'toLowerCase' sampleObject.verb = 'Not' sampleObject.nounOne = 'Small' sampleObject.nounTwo = 'Pretty' expect(objectA.prop1).to.equal 'The following text is not (not) small and pretty' describe "Transforms", ()-> it "can bind an object\'s property to another\'s with a transform", ()-> objectA.prop2 = 'current' bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)-> newValue+'+'+currentValue ) expect(objectB.prop2).to.equal 'current+current' objectA.prop2 = 'new' expect(objectB.prop2).to.equal 'new+current+current' objectA.prop2 = 'new' expect(objectB.prop2).to.equal 'new+current+current' objectA.prop2 = 'newer' expect(objectB.prop2).to.equal 'newer+new+current+current' it "can bind an object\'s property to another\'s with a promise transform that resolves async", (done)-> restartSandbox() objectA.prop2 = 'current' bound = SimplyBind('prop2', {'promiseTransforms':true}).of(objectA) .to('prop2').of(objectB) .transform (newValue, currentValue)-> new Promise (resolve)-> resolve(newValue+'+'+currentValue) setTimeout ()-> expect(objectB.prop2).to.equal 'current+current' objectA.prop2 = 'new' setTimeout ()-> expect(objectB.prop2).to.equal 'new+current+current' done() , 0 , 0 it "can bind with a transform both ways", ()-> restartSandbox() objectA.prop2 = 'current' bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)-> newValue+'+'+currentValue ).bothWays() expect(objectB.prop2).to.equal 'current+current' objectA.prop2 = 'new' expect(objectB.prop2).to.equal 'new+current+current' objectA.prop2 = 'new' expect(objectB.prop2).to.equal 'new+current+current' objectB.prop2 = 'new' expect(objectA.prop2).to.equal 'new+new' objectB.prop2 = 'newer' expect(objectA.prop2).to.equal 'newer+new+new' it "can bind with multiple transforms in a single chain", ()-> restartSandbox() objectA.prop1 = 'CuRRent' SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transform((value)-> value.toUpperCase() ).and('prop3').of(objectB).transform((value)-> value.toLowerCase() ).and('prop4').of(objectB).transform (value)-> value.slice 0, 4 expect(objectA.prop1).to.equal 'CuRRent' expect(objectB.prop1).to.equal 'CuRRent' expect(objectB.prop2).to.equal 'CURRENT' expect(objectB.prop3).to.equal 'current' expect(objectB.prop4).to.equal 'CuRR' it "can apply a single transform to all bindings in a chain", ()-> restartSandbox() SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transformAll (value)-> value.toUpperCase() SimplyBind('prop1').of(objectA).to('prop3').of(objectB).and('prop4').of objectB objectA.prop1 = 'all at once' expect(objectB.prop1).to.equal 'ALL AT ONCE' expect(objectB.prop2).to.equal 'ALL AT ONCE' expect(objectB.prop3).to.equal 'all at once' expect(objectB.prop4).to.equal 'all at once' describe "Arrays", ()-> describe "As property value", ()-> it "supports live properties", ()-> restartSandbox() SimplyBind(0).of(arrayA).to(0).of arrayB arrayA[0] = 'live prop change :)' expect(arrayB[0]).to.equal 'live prop change :)' it "should avoid infinite loops", ()-> restartSandbox() # ==== Standard objects ================================================================================= SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays() SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays() SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays() arrayA[0] = 'arrayA' expect(arrayB[0]).to.equal 'arrayA' expect(arrayC[0]).to.equal 'arrayA' arrayB[0] = 'arrayB' expect(arrayA[0]).to.equal 'arrayB' expect(arrayC[0]).to.equal 'arrayB' it "can bind an array\'s property to another\'s", ()-> restartSandbox() bound = SimplyBind(0).of(arrayA).to(0).of(arrayB) bound.set 'changed' expect(arrayB[0]).to.equal 'changed' it "can bind an object\'s property to another\'s even if the value is falsy", ()-> restartSandbox() bound = SimplyBind(1).of(arrayA).to(1).of(arrayB) bound.set '' expect(arrayB[1]).to.equal '' bound.set 0 expect(arrayB[1]).to.equal 0 bound.set false expect(arrayB[1]).to.equal false bound.set undefined expect(arrayB[1]).to.equal false it "can bind an object\'s property to multiple other properties", ()-> restartSandbox() SimplyBind(0).of(arrayA).to(0).of(arrayB).and(1).of(arrayB).and(2).of(arrayB).and(3).of arrayB arrayA[0] = 'all at once' expect(arrayB[0]).to.equal 'all at once' expect(arrayB[1]).to.equal 'all at once' expect(arrayB[2]).to.equal 'all at once' expect(arrayB[3]).to.equal 'all at once' it "can unbind all bindings", ()-> restartSandbox() arrayA[0] = 'some string' modified = false bound = SimplyBind(0).of(arrayA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()-> modified = true ) expect(objectB.prop1).to.equal 'some string' expect(objectB.prop2).to.equal 'some string' expect(objectC.prop1).to.equal 'some string' expect(objectC.prop2).to.equal 'some string' expect(textarea.value).to.equal 'some string' expect(modified).to.equal true modified = false bound.unBind() arrayA[0] = 'should change' expect(modified).to.equal false expect(objectB.prop1).to.equal 'should change' expect(objectB.prop2).to.equal 'should change' expect(objectC.prop1).to.equal 'should change' expect(objectC.prop2).to.equal 'should change' expect(textarea.value).to.equal 'should change' SimplyBind.unBindAll arrayA arrayA[0] = 'shouldn\'t change' expect(objectB.prop1).to.equal 'should change' expect(objectB.prop2).to.equal 'should change' expect(objectC.prop1).to.equal 'should change' expect(objectC.prop2).to.equal 'should change' expect(textarea.value).to.equal 'should change' describe "As direct array", ()-> # it("should avoid infinite loops", function(){ # restartSandbox(); # SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays(); # SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays(); # SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays(); # arrayA[0] = 'arrayA'; # expect(arrayB[0]).to.be('arrayA'); # expect(arrayC[0]).to.be('arrayA'); # arrayB[0] = 'arrayB'; # expect(arrayA[0]).to.be('arrayB'); # expect(arrayC[0]).to.be('arrayB'); # }); it "can bind an array to anything and update dependents even when calling the .push, .pop, .shift, .unshift, .splice, .reverse, and .sort methods", ()-> sampleArray = [1,2,3,4,5,6,7,8,9,10] mutations = 0 SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++ expect(objectB.prop4.length).to.equal 10 expect(mutations).to.equal 1 sampleArray.push 11 expect(objectB.prop4.length).to.equal 11 expect(mutations).to.equal 2 sampleArray.shift() sampleArray.shift() expect(objectB.prop4.length).to.equal 9 expect(mutations).to.equal 4 sampleArray.unshift 2 sampleArray.unshift 1 expect(objectB.prop4.length).to.equal 11 expect(mutations).to.equal 6 sampleArray.pop() sampleArray.pop() expect(objectB.prop4.length).to.equal 9 expect(mutations).to.equal 8 sampleArray.splice 0, 5 expect(objectB.prop4.length).to.equal 4 expect(mutations).to.equal 9 sampleArray.reverse() expect(objectB.prop4.length).to.equal 4 expect(mutations).to.equal 10 sampleArray.sort() expect(objectB.prop4.length).to.equal 4 expect(mutations).to.equal 11 sampleArray.sort ()-> 1 expect(objectB.prop4.length).to.equal 4 expect(mutations).to.equal 12 it "it\'s impossible to replace the array object in an array binding.", ()-> sampleArray = [1,2,3,4,5,6,7,8,9,10] mutations = 0 SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++ expect(objectB.prop4.length).to.equal 10 expect(mutations).to.equal 1 SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10] # Replace array. If it were to replace it, the mutations count will increase by one. SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10] SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10] sampleArray.push 11 expect(objectB.prop4.length).to.equal 11 expect(mutations).to.equal 2 sampleArray.shift() sampleArray.shift() expect(objectB.prop4.length).to.equal 9 expect(mutations).to.equal 4 sampleArray.unshift 2 sampleArray.unshift 1 expect(objectB.prop4.length).to.equal 11 expect(mutations).to.equal 6 sampleArray.pop() sampleArray.pop() expect(objectB.prop4.length).to.equal 9 expect(mutations).to.equal 8 sampleArray.splice 0, 5 expect(objectB.prop4.length).to.equal 4 expect(mutations).to.equal 9 it "will update dependents when its children get modified if specified via the trackArrayChildren option", ()-> sampleArray = [1,2,3,4,5,6,7,8,9,10] sampleArray2 = [1,2,3,4,5,6,7,8,9,10] mutations = 0 SimplyBind(sampleArray).to('prop5').of(objectA).and ()-> mutations++ expect(objectA.prop5).to.equal sampleArray sampleArray[0] = 100 sampleArray[1] = 200 sampleArray[2] = 300 expect(objectA.prop5[0]).to.equal 100 expect(objectA.prop5[1]).to.equal 200 expect(objectA.prop5[2]).to.equal 300 expect(mutations).to.equal 1 mutations = 0 SimplyBind(sampleArray2, 'trackArrayChildren': true).to('prop6').of(objectA).and ()-> mutations++ expect(objectA.prop6).to.equal sampleArray2 sampleArray2[0] = 100 sampleArray2[1] = 200 sampleArray2[2] = 300 expect(objectA.prop6[0]).to.equal 100 expect(objectA.prop6[1]).to.equal 200 expect(objectA.prop6[2]).to.equal 300 expect(mutations).to.equal 4 it "will update dependents even when there is a sepearate binding on a reference of the same array", ()-> sampleArrayA = [1,2,3,4,5,6,7,8,9,10] sampleArrayB = sampleArrayA sampleArrayC = null mutationsA = 0 mutationsB = 0 mutationsC = 0 SimplyBind(sampleArrayA) .to('prop6').of(objectA) .and ()-> mutationsA++ SimplyBind(sampleArrayB) .to('prop6').of(objectB) .and (arr)-> sampleArrayC = arr unless sampleArrayC .a