hannahhoward / a1atscript

The Angular 2 Polyfill
MIT License
101 stars 7 forks source link

bind-attribute being overwritten to undefined in angular 1.4.1 #8

Closed timkindberg closed 9 years ago

timkindberg commented 9 years ago

Given using angular 1.4.1 and a component such as this:

import {Component, View} from 'a1atscript';

@Component({
  selector: "child",
  properties: {
    data: 'data'
  }
})
@View({
  inline: `<div>{{child.data | json}}</div>`
})
export default class Child { }

When I use it in another component, like this:

import {Component, View} from 'a1atscript';

@Component({
  selector: "parent"
})
@View({
  inline: `<child bind-data="parent.dataForChild"></child>`
})
export default class Parent { 
  constructor() {
    this.dataForChild = {foo: 'bar'};
  }
}

I end up seeing nothing rendered out in Child. When I look at it in dev tools, I see it set to undefined, then {foo: 'bar'}, then (and here's the problem) undefined again.

What is happening is this:

  1. two attributes are set up by a1atscript on the Child directive, data and bind-data.
  2. data is initialized to undefined, setting Child.data to undefined
  3. bind-data is set via the PropertiesBuilder to {foo: 'bar'}, setting Child.data to undefined
  4. BAD STUFF: data is set to undefined again... wat?! Apparrently via bind again. I traced it to a change made in Angular 1.4.1: https://github.com/angular/angular.js/blame/master/src/ng/compile.js#L1192-L1193

I think the workaround needs to be that a1atscript disallows usage of both the regular attr (attr) and the bound version of the attr (bind-attr). Obviously both attrs need to be set up, but then when the user uses one, it should somehow cancel out the other somehow. So if I use bind-attr, then attr knows to just stay out of the way.

timkindberg commented 9 years ago

Temporary workaround is to create a setter for the property that doesn't allow it to be set back to undefined (which may not be feasible for some use cases). This code will only ever allow data to be undefined once—at first initialization—after that it can only be set to a non-undefined value:

export default class Child {
  set data(val) {
    this._data = val !== undefined ? val : this._data;
  }
}