test('two-way binding syntax INTRODUCED in v2.3 ALLOWS a child property to initialize an undefined parent property', function(){
			var renderer = stache('<pa-rent/>');

			Component.extend({
			 tag : 'pa-rent',
			 view: stache('<chi-ld childProp:bind="parentProp" />')
		 });

			Component.extend({
			 tag : 'chi-ld',
			 ViewModel: {
				childProp: { value: 'bar' }
			}
		});

			var frag = renderer({});

			var parentVM = canViewModel(frag.firstChild);
			var childVM = canViewModel(frag.firstChild.firstChild);

			equal(parentVM.get("parentProp"), 'bar', 'parentProp is bar');
			equal(childVM.get("childProp"), 'bar', 'childProp is bar');

			parentVM.set("parentProp",'foo');

			equal(parentVM.get("parentProp"), 'foo', 'parentProp is foo');
			equal(childVM.get("childProp"), 'foo', 'childProp is foo');

			childVM.set("childProp",'baz');

			equal(parentVM.get("parentProp"), 'baz', 'parentProp is baz');
			equal(childVM.get("childProp"), 'baz', 'childProp is baz');
		});
	test('one way - child to parent - importing viewModel hyphenatedProp:to="test"', function(){
		MockComponent.extend({
			tag: 'import-prop-scope',
			template: stache('Hello {{userName}}'),
			viewModel: {
				userName: '******',
				age: 7,
				updateName: function(){
					this.set('userName', 'Justin');
				}
			}
		});

		MockComponent.extend({
			tag: 'import-prop-parent',
			template: stache('<import-prop-scope vm:userName:to="test" vm:this:to="childComponent"></import-prop-scope>' +
				'<div>Imported: {{test}}</div>')
		});

		var template = stache('<import-prop-parent></import-prop-parent>');
		var frag = template({});
		var importPropParent = frag.firstChild;
		var importPropScope = importPropParent.getElementsByTagName("import-prop-scope")[0];

		canViewModel(importPropScope).updateName();

		var importPropParentViewModel = canViewModel(importPropParent);

		equal(importPropParentViewModel.get("test"), "Justin", "got hyphenated prop");

		equal(importPropParentViewModel.get("childComponent"), canViewModel(importPropScope), "got view model");

	});
Example #3
0
test('Should configure chart using a passed config', 1, (assert) => {
	let tpl = '<bit-c3 {config}="config"><bit-c3-data><bit-c3-data-column /></bit-c3-data></bit-c3>';
	let frag = stache(tpl)({
		config: {
			axis: {
				x: {
					type: 'category',
					tick: { rotate: -45, multiline: false },
					height: 130
				}
			}
		}
	});
	let vm = canViewModel(frag.querySelector('bit-c3'));
	assert.deepEqual(vm.config, {
		data: { columns:[], x:'x' },
		axis: {
			x: {
				type:'category',
				tick: { rotate: -45, multiline: false },
				height: 130
			}
		},
		bindto: undefined
	}, 'Config object is defined correctly');
});
	test("viewModel not rebound correctly (#550)", function () {

		var nameChanges = 0;

		Component.extend({
			tag: "viewmodel-rebinder",
			events: {
				"{name}": function () {
					nameChanges++;
				}
			}
		});

		var renderer = stache("<viewmodel-rebinder></viewmodel-rebinder>");

		var frag = renderer();
		var viewModel = canViewModel(frag.firstChild);

		var n1 = new SimpleObservable(),
		n2 = new SimpleObservable();

		viewModel.set("name", n1);

		n1.set("updated");

		viewModel.set("name", n2);

		n2.set("updated");


		equal(nameChanges, 2);
	});
	test("one-way pass computes to components with ~", function(assert) {
		expect(6);
		MockComponent.extend({
			tag: "foo-bar"
		});

		var baseVm = new SimpleMap({foo : "bar"});

		this.fixture.appendChild(stache("<foo-bar compute:from=\"~foo\"></foo-bar>")(baseVm));

		var vm = canViewModel(this.fixture.firstChild);
		ok(vm.get("compute")[canSymbol.for('can.getValue')], "observable returned");
		equal(vm.get("compute")(), "bar", "Compute has correct value");

		canReflect.onValue(vm.get("compute"), function() {
			// NB: This gets called twice below, once by
			//  the parent and once directly.
			ok(true, "Change handler called");
		});

		baseVm.set("foo", "quux");
		equal(vm.get("compute")(), "quux", "Compute updates");

		vm.get("compute")("xyzzy");
		equal(baseVm.get("foo"), "xyzzy", "Compute does update the other direction");
	});
		test("id and class should work now (#694)", function () {
			Component.extend({
			 tag: "stay-classy",
			 ViewModel: SimpleMap.extend({
				setup: function(props){
					canReflect.assign(props, {
						notid: "foo",
						notclass: 5,
						notdataviewid: {}
					});
					return SimpleMap.prototype.setup.apply(this, arguments);
				}
			})
		 });

			var data = {
			 idData: "id-success",
			 classData: "class-success"
		 };

		 var frag = stache(
		 "<stay-classy id:bind='idData'" +
		 " class:bind='classData'></stay-classy>")(data);

		 var stayClassy = frag.firstChild;

		 domMutateNode.appendChild.call(this.fixture, frag);

		 var viewModel = canViewModel(stayClassy);

		 equal(viewModel.get("id"), "id-success");
		 equal(viewModel.get("class"), "class-success");
	 });
	test("function reference to child (#2116)", function(){
		expect(2);
		var template = stache('<foo-bar vm:child:from="parent"></foo-bar>');
		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : {
				method: function(){
					ok(false, "should not be called");
				}
			}
		});

		var VM = SimpleMap.extend({
			parent : function() {
				ok(false, "should not be called");
			}
		});

		var vm = new VM({});
		var frag = template(vm);

		equal( typeof canViewModel(frag.firstChild).attr("child"), "function", "to child binding");


		template = stache('<foo-bar vm:method:to="vmMethod"></foo-bar>');
		vm = new VM({});
		template(vm);

		ok(typeof vm.attr("vmMethod") === "function", "parent export function");
	});
	test('one-way - child to parent - viewModel - with converters', function(){
		MockComponent.extend({
			tag: "view-model-able",
			viewModel: function(){
				return new SimpleMap({viewModelProp: "Mercury"});
			}
		});

		stache.addConverter("upper-case", {
			get: function( fooCompute ) {
				return (""+canReflect.getValue(fooCompute)).toUpperCase();
			},
			set: function( newVal, fooCompute ) {
				canReflect.setValue(fooCompute, (""+newVal).toUpperCase() );
			}
		});

		var template = stache("<view-model-able vm:viewModelProp:to='upper-case(scopeProp)'/>");

		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.get("viewModelProp"), "Mercury", "initial value kept" );
		equal( map.get("scopeProp"), "MERCURY", "initial value set on parent, but upper cased" );

		viewModel.set("viewModelProp", "Earth");
		equal(map.get("scopeProp"), "EARTH", "binding from child to parent updated");

		map.set("scopeProp", "Mars");
		equal( viewModel.get("viewModelProp"), "Earth", "no binding from parent to child" );
	});
		var handler = function(ev) {
			var attrVal = el.getAttribute(encoder.encode(attributeName));
			if (!attrVal) {
				return;
			}

			var viewModel = canViewModel(el);

			// expression.parse will read the attribute
			// value and parse it identically to how mustache helpers
			// get parsed.
			var expr = expression.parse(attrVal, {
				lookupRule: function() {
					return expression.Lookup;
				},
				methodRule: "call"
			});

			var runScope = makeScopeFromEvent(el, ev, viewModel, arguments, data, bindingContext);

			if (expr instanceof expression.Hashes) {
				var hashExprs = expr.hashExprs;
				var key = Object.keys(hashExprs)[0];
				var value = expr.hashExprs[key].value(runScope);
				var isObservableValue = canReflect.isObservableLike(value) && canReflect.isValueLike(value);
				runScope.set(key, isObservableValue ? canReflect.getValue(value) : value);
			} else if (expr instanceof expression.Call) {
				runEventCallback(el, ev, data, runScope, expr, attributeName, attrVal);
			} else {
				throw new Error("can-stache-bindings: Event bindings must be a call expression. Make sure you have a () in " + data.attributeName + "=" + JSON.stringify(attrVal));
			}
		};
	test("two way - viewModel (#1700)", function(){

		var template = stache("<div vm:viewModelProp:bind='scopeProp'/>");
		var map = new SimpleMap({ scopeProp: "Hello" });

		var scopeMapSetCalled = 0;

		// overwrite setKeyValue to catch child->parent updates
		var origMapSetKeyValue = map[canSymbol.for("can.setKeyValue")];
		map[canSymbol.for("can.setKeyValue")] = function(attrName, value){
			if(typeof attrName === "string" && arguments.length > 1) {
				scopeMapSetCalled++;
			}

			return origMapSetKeyValue.apply(this, arguments);
		};

		// RENDER
		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal(scopeMapSetCalled, 0, "set is not called on scope map");
		equal(viewModel.get("viewModelProp"), "Hello", "initial value set" );

		viewModel = canViewModel(frag.firstChild);

		var viewModelSetCalled = 1; // set once already - on "initial value set"
		var origViewModelSet = viewModel[canSymbol.for("can.setKeyValue")];
		viewModel[canSymbol.for("can.setKeyValue")] = function(attrName){
			if(typeof attrName === "string" && arguments.length > 1) {
				viewModelSetCalled++;
			}

			return origViewModelSet.apply(this, arguments);
		};
		viewModel.set("viewModelProp", "HELLO");
		equal(map.get("scopeProp"), "HELLO", "binding from child to parent");
		equal(scopeMapSetCalled, 1, "set is called on scope map");
		equal(viewModelSetCalled, 2, "set is called viewModel");

		map.set("scopeProp", "WORLD");
		equal(viewModel.get("viewModelProp"), "WORLD", "binding from parent to child" );
		equal(scopeMapSetCalled, 1, "can.setKey is not called again on scope map");
		equal(viewModelSetCalled, 3, "set is called again on viewModel");
	});
	test('two-way - reference - child:bind="scope.vars.ref" (#1700)', function(){
		var data = new SimpleMap({person: new SimpleMap({name: new SimpleMap({})}) });
		MockComponent.extend({
			tag: 'reference-export',
			viewModel: function(){
				return new SimpleMap({tag: 'reference-export'});
			}
		});
		MockComponent.extend({
			tag: 'ref-import',
			viewModel: function(){
				return new SimpleMap({tag: 'ref-import'});
			}
		});

		var template = stache("<reference-export name:bind='scope.vars.refName'/>"+
			"<ref-import name:bind='scope.vars.refName'/> {{helperToGetScope()}}");

		var scope;
		var frag = template(data,{
			helperToGetScope: function(options){
				scope = options.scope;
			}
		});

		var refExport = canViewModel(frag.firstChild);
		var refImport = canViewModel(frag.firstChild.nextSibling);

		refExport.set("name", "v1");

		equal( scope.peek("scope.vars.refName"), "v1", "reference scope updated");

		equal(refImport.get("name"), "v1", "updated ref-import");

		refImport.set("name", "v2");

		equal(refExport.get("name"), "v2", "updated ref-export");

		equal( scope.peek("scope.vars.refName"), "v2", "actually put in refs scope");

	});
	test("canViewModel utility", function() {
		Component({
			tag: "my-taggy-tag",
			view: stache("<h1>hello</h1>"),
			viewModel: function(){
				return new SimpleMap({
					foo: "bar"
				});
			}
		});

		var frag = stache("<my-taggy-tag id='x'></my-taggy-tag>")();


		var el = frag.firstChild;

		equal(canViewModel(el), el[canSymbol.for('can.viewModel')], "one argument grabs the viewModel object");
		equal(canViewModel(el, "foo"), "bar", "two arguments fetches a value");
		canViewModel(el, "foo", "baz");
		equal(canViewModel(el, "foo"), "baz", "Three arguments sets the value");
	});
	test("standard attributes should not set viewModel props", function(){
		MockComponent.extend({
			tag: "test-elem",
			viewModel: SimpleMap
		});

		var template = stache("<test-elem foo=\"bar\"/>");

		var frag = template(new SimpleMap({
			bar: true
		}));

		var vm = canViewModel(frag.firstChild);

		equal(vm.get('foo'), undefined);
	});
	test('one-way - parent to child - viewModel', function(){


		var template = stache("<div vm:viewModelProp:from='scopeProp'/>");


		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.attr("viewModelProp"), "Venus", "initial value set" );

		viewModel.attr("viewModelProp", "Earth");
		equal(map.attr("scopeProp"), "Venus", "no binding from child to parent");

		map.attr("scopeProp", "Mars");
		equal( viewModel.attr("viewModelProp"), "Mars", "binding from parent to child" );
	});
QUnit.test("ViewModel properties default to DefineList if set to an Array (#225)", function() {
	Component.extend({
		tag: "viewmodel-lists",
		view: "Hello, World",
		ViewModel: {
			items: {
				default: function() {
					return [ "one", "two" ];
				}
			}
		}
	});

	var renderer = stache("<viewmodel-lists></viewmodel-lists>");

	var fragOne = renderer();
	var vm = viewModel(fragOne.firstChild);

	QUnit.ok(vm.items instanceof define.DefineList, 'vm is a DefineList');
});
	QUnit.test("an object is turned into a SimpleMap as viewModel", function() {
		Component.extend({
		 tag: "can-map-viewmodel",
		 view: stache("{{name}}"),
		 viewModel: {
			name: "Matthew"
		}
	});

		var renderer = stache("<can-map-viewmodel></can-map-viewmodel>");

		var fragOne = renderer();
		var vmOne = canViewModel(fragOne.firstChild);

		var fragTwo = renderer();

		vmOne.set("name", "Wilbur");

		equal(fragOne.firstChild.firstChild.nodeValue, "Wilbur", "The first map changed values");
		equal(fragTwo.firstChild.firstChild.nodeValue, "Matthew", "The second map did not change");
	});
QUnit.test('Works with can-define', function () {

	var VM = define.Constructor({
		firstName: {
			type: 'string'
		},
		lastName: {
			type: 'string'
		},
		fullName: {
			get: function () {
				return [this.firstName, this.lastName].join(' ');
			}
		}
	});

	Component.extend({
		tag: 'can-define-component',
		ViewModel: VM,
		view: stache('Name: {{fullName}}')
	});

	var frag = stache('<can-define-component firstName:from="firstName" lastName:from="lastName" />')({
		firstName: 'Chris',
		lastName: 'Gomez'
	});

	var vm = viewModel(frag.firstChild);

	QUnit.ok(vm instanceof VM, 'Constructor was called');
	QUnit.equal(vm.firstName, 'Chris', 'ViewModel was set from scope');
	QUnit.equal(vm.lastName, 'Gomez', 'ViewModel was set from scope');
	QUnit.equal(frag.firstChild.innerHTML, 'Name: Chris Gomez', 'Rendered fullName');

	vm.firstName = 'Justin';
	vm.lastName = 'Meyer';

	QUnit.equal(frag.firstChild.innerHTML, 'Name: Justin Meyer', 'Rendered fullName after change');
});
		test('Component two way binding loop (#1579)', function() {
			var changeCount = 0;

			Component.extend({
				tag: 'product-swatch-color',
				viewModel: {
					tag: 'product-swatch-color'
				}
			});


			Component.extend({
				tag: 'product-swatch',
				view: stache('<product-swatch-color variations:bind="variations"></product-swatch-color>'),
				ViewModel: DefineMap.extend({

					variations: {
						set: function(variations) {
							if(changeCount > 500) {
								return;
							}
							changeCount++;
							return new DefineList(variations.get());
						}
					}

				})
			});

			var frag = stache('<product-swatch></product-swatch>')(),
			productSwatch = frag.firstChild;


			canViewModel( productSwatch ).set('variations', new DefineList());



			ok(changeCount < 500, "more than 500 events");
		});
QUnit.test("ViewModel defaults to DefineMap if set to an Object", function() {
	Component.extend({
		tag: 'can-define-component',
		ViewModel: {
			firstName: {
				type: 'string'
			},
			lastName: {
				type: 'string'
			},
			fullName: {
				get: function () {
					return [this.firstName, this.lastName].join(' ');
				}
			}
		},
		view: stache('Name: {{fullName}}')
	});

	var frag = stache('<can-define-component firstName:from="firstName" lastName:from="lastName" />')({
		firstName: 'Chris',
		lastName: 'Gomez'
	});

	var vm = viewModel(frag.firstChild);

	QUnit.ok(vm instanceof DefineMap, 'vm is a DefineMap');
	QUnit.equal(vm.firstName, 'Chris', 'ViewModel was set from scope');
	QUnit.equal(vm.lastName, 'Gomez', 'ViewModel was set from scope');
	QUnit.equal(frag.firstChild.innerHTML, 'Name: Chris Gomez', 'Rendered fullName');

	vm.firstName = 'Justin';
	vm.lastName = 'Meyer';

	QUnit.equal(frag.firstChild.innerHTML, 'Name: Justin Meyer', 'Rendered fullName after change');
});
	test('one-way - child to parent - viewModel', function(){
		MockComponent.extend({
			tag: "view-model-able",
			viewModel: function(){
				return new SimpleMap({viewModelProp: "Mercury"});
			}
		});

		var template = stache("<view-model-able vm:viewModelProp:to='scopeProp'/>");

		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.get("viewModelProp"), "Mercury", "initial value kept" );
		equal( map.get("scopeProp"), "Mercury", "initial value set on parent" );

		viewModel.set("viewModelProp", "Earth");
		equal(map.get("scopeProp"), "Earth", "binding from child to parent");

		map.set("scopeProp", "Mars");
		equal( viewModel.get("viewModelProp"), "Earth", "no binding from parent to child" );
	});
		QUnit.test("one-way - child to parent - parent that does not leak scope, but has no view", function(){

			Component.extend({
				tag: "outer-noleak",
				ViewModel: DefineMap.extend("Outer", {}, {
					name: { default: "outer" },
					myChild: { default: null }
				}),
				leakScope: false
			});
			Component.extend({
				tag: "my-child",
				ViewModel : DefineMap.extend("Inner", {}, {
					name: { default: "inner" }
				}),
				leakScope: false
			});

			var renderer = stache("<outer-noleak><my-child this:to='myChild'/></outer-noleak>");
			var frag = renderer();
			var vm = canViewModel(frag.firstChild);
			QUnit.equal(vm.myChild.name,"inner", "got instance");

		});
			getViewModel = ObservationRecorder.ignore(function() {
				return viewModel || (viewModel = canViewModel(el));
			}),
Example #23
0
		inserted: function(viewModel, ev) {
			this.viewModel.chart = canViewModel(this.element.parentElement).chart;
			this.viewModel.updateName();
		},
Example #24
0
export const LFeatureLayer = Component.extend({
    tag: 'l-feature-layer',
    ViewModel: DefineMap.extend({
        url: 'string',
        _layer: '*',
        _map: {
            set (map) {
                this._layer = new FeatureLayer({url: this.url});
                this._layer.addTo(map);
                console.log(map);
                return map;
            }
        },
        destroy () {
            console.log('Dstroying!!');
            this._map.removeLayer(this._layer);
            this._layer = null;
            this._map = null;
        }
    }),
    events: {
        inserted (element) {
            debugger;
            const lmap = canViewModel(element.parentElement);
            if (lmap && lmap.mapObject) {
                this.viewModel._map = lmap.mapObject;
            }
        }
    }
});
Example #25
0
 inserted: function () {
     this.viewModel.parent = canViewModel(this.element.parentNode);
     if (this.viewModel.parent && this.viewModel.parent.addPage) {
         this.viewModel.parent.addPage(this.viewModel);
     }
 },
Example #26
0
	testIfRealDocument("Bi-directional binding among sibling components, new syntax (#325)", function () {
		var groupCollapsed = console.groupCollapsed;
		if(groupCollapsed) {
			console.groupCollapsed = null; //no op
		}


		var demoContext = new DefineMap({
			person: ''
		});

		var SourceComponentVM = DefineMap.extend("SourceComponentVM",{
			defaultPerson: {
				value: 'John'
			},
			person: {
				set: function(val) {
					return val || this.defaultPerson;
				}
			}
		});

		var ClearComponentVM = DefineMap.extend("ClearComponentVM",{
			person: 'string',
			clearPerson: function() {
				this.set('person', '');
			}
		});

		MockComponent.extend({
			tag: "source-component",
			viewModel: SourceComponentVM,
			template: stache('<span>{{person}}</span><input type="text" value:bind="./person" />')
		});

		MockComponent.extend({
			tag: "clear-button",
			viewModel: ClearComponentVM,
			template: stache('<input type="button" value="Clear" on:click="./clearPerson()" /><span>{{./person}}</span>')
		});

		var demoRenderer = stache(
			'<span>{{./person}}</span>' +
			'<source-component person:bind="./person" />' +
			'<clear-button person:bind="./person" />'
		);

		var frag = demoRenderer(demoContext);

		var sourceComponentVM = canViewModel(frag.childNodes[1]);
		var clearButtonVM = canViewModel(frag.childNodes[2]);

		QUnit.equal(frag.childNodes[0].childNodes[0].nodeValue, '', "demoContext person is empty");
		QUnit.equal(frag.childNodes[1].childNodes[0].childNodes[0].nodeValue, 'John', "source-component person is default");
		QUnit.equal(frag.childNodes[2].childNodes[1].childNodes[0].nodeValue, '', "clear-button person is empty");

		sourceComponentVM.person = 'Bob';

		QUnit.equal(frag.childNodes[0].childNodes[0].nodeValue, 'Bob', "demoContext person set correctly");
		QUnit.equal(frag.childNodes[1].childNodes[0].childNodes[0].nodeValue, 'Bob', "source-component person set correctly");
		QUnit.equal(frag.childNodes[2].childNodes[1].childNodes[0].nodeValue, 'Bob', "clear-button person set correctly");

		clearButtonVM.clearPerson();

		// Note that 'John' will not be set on the parent or clear button because parent was already set
		// to an empty string and the bindingSemaphore will not allow another change to the parent
		// (giving the parent priority) to prevent cyclic dependencies.
		QUnit.equal(frag.childNodes[0].childNodes[0].nodeValue, '', "demoContext person set correctly");
		QUnit.equal(frag.childNodes[1].childNodes[0].childNodes[0].nodeValue, 'John', "source-component person set correctly");
		QUnit.equal(frag.childNodes[2].childNodes[1].childNodes[0].nodeValue, '', "clear-button person set correctly");

		if(groupCollapsed) {
			console.groupCollapsed = groupCollapsed;
		}
	});
Example #27
0
	$.fn.viewModel = function(){
		return canViewModel(this[0]);
	};
Example #28
0
         this.visible = false;
         this.hideAll();
     }
     return false;
 },
 /**
  * Queries the dom for other dropdown-menu components and hides them.
  * This is used when a dropdown component is visible and another one is
  * clicked, any others will be made invisible
  * @function hideAll
  * @signature `hideAll()`
  */
 hideAll () {
     const nodes = document.querySelectorAll('dropdown-menu');
     for (let i = 0; i < nodes.length; i ++) {
         const vm = canViewModel(nodes[i]);
         if (vm.visible) {
             vm.visible = false;
         }
     }
 },
 /**
  * When a primary button is clicked, this function dispatches the `primaryclick`
  * event with the button that was clicked as its argument.
  * @function onPrimaryClick
  * @param {ButtonObject} button the button that was clicked
  * @param {MouseEvent} event The mouse click event on the button that we should prevent default
  * @return {Boolean} returns false to prevent event from changing page route
  */
 onPrimaryClick (button, event) {
     if (event) {
Example #29
0
    hidePopup () {
        this.overlay.setPosition(undefined);
        this.modalActive = false;
    }
});

assign(ViewModel.prototype, CanEvent);

/**
 * @module {can.Component} ol-popup <ol-popup />
 * @parent geo.components
 */
export const OlPopup = Component.extend({
    tag: 'ol-popup',
    view: template,
    ViewModel: ViewModel,
    leakScope: true,
    events: {
        inserted () {
            var mapViewModel = canViewModel(this.element.parentNode);
            this.viewModel.overlayElement = this.element.querySelector('.ol-popup');
            this.viewModel.map = mapViewModel.mapObject;
        },
        removed () {
            if (this.viewModel.overlay && this.viewModel.map) {
                this.viewModel.map.removeOverlay(this.overlay);
            }
        }
    }
});
		test("conditional attributes (#2077)", function(){

			Component.extend({
			 tag: 'some-comp',
			 ViewModel: DefineMap.extend({ seal: false }, {})
		 });
			var renderer = stache("<some-comp "+
			"{{#if preview}}next:from='nextPage'{{/if}} "+
			"swap:from='{{swapName}}' "+
			"{{#preview}}checked{{/preview}} "+
			"></some-comp>");

			var map = new SimpleMap({
			 preview: true,
			 nextPage: 2,
			 swapName: "preview"
		 });
			var frag = renderer(map);

			var vm = canViewModel(frag.firstChild);

			var threads = [
			function(){

				equal(vm.next, 2, "has binding initially");
				equal(vm.swap, true, "swap - has binding");
				//equal(vm.get("checked"), "", "attr - has binding"); (commented out because we don't do this sort of binding)
				map.attr("preview", false);
			},
			function(){
				equal(vm.swap, false, "swap - updated binidng");

				//ok(vm.get("checked") === null, "attr - value set to null");

				map.attr("nextPage", 3);
				equal(vm.next, 2, "not updating after binding is torn down");
				map.attr("preview", true);

			},
			function(){
				equal(vm.next, 3, "re-initialized with binding");
				equal(vm.swap, true, "swap - updated binidng");
				//equal(vm.get("checked"), "", "attr - has binding set again");
				map.attr("swapName", "nextPage");
			},
			function(){
				equal(vm.swap, 3, "swap - updated binding key");
				map.attr("nextPage",4);
				equal(vm.swap, 4, "swap - updated binding");
			}
			];
			stop();
			var index = 0;
			var next = function(){
			 if(index < threads.length) {
				threads[index]();
				index++;
				setTimeout(next, 150);
			} else {
				start();
			}
		};
		setTimeout(next, 100);
	});