ken.dunnington
ken.dunnington

Reputation: 905

Binding an integer to AngularJS 1.5 component

When using attribute binding in components, the data passed to the controller is always a string. I'm trying to pass an integer, however, and am having trouble converting it from a string and having the conversion stick.

I've tried saving the data as an integer in $onInit() but outside of this function, the data returns to its original state (type and value). I understand that components should not modify the data passed in as a general rule, but since this is an attribute binding, and the data is passed by value, I didn't think that applied.

function IntegerBindingController() {
  this.$onInit = function() {
    // Assuming 'number="2"' in the HTML
    // This only changes the data inside this function
    this.number = parseInt(this.number)
    this.typeofNumber = typeof this.number // evaluates to 'number'
    this.simpleAdd = this.number + 5 // evaluates to 7
    this.dataAdd = this.numberOneWay + 5
    console.log(this)
  }

  this.test = function() {
    // this.number is a string inside this function
    this.typeofNumber = typeof this.number // evaluates to 'string'
    this.simpleAdd = this.number + 5 // evaluates to 25
  }
}

I can solve this by copying the data to a new property on the controller, but I'm curious if someone can explain what's happening here. See this Plunker for a working example of the issue.

Upvotes: 0

Views: 3465

Answers (2)

ken.dunnington
ken.dunnington

Reputation: 905

The solution I ended up going with was to use $onChanges to handle the bound data values. In my case, at least one of the values could potentially change after an async call in the parent component, so this made sense overall. As Prinay Panday notes above, the @ binding always comes through as a string. The $onInit() method guarantees that bindings will be available, but it doesn't guarantee that they will change, so even if you change the value on the component, Angular can change it later. That's another reason why the documentation recommends copying the bound values to a local variable if you need to manipulate them at all. As for the $onChanges() solution, it would look like this

function IntegerBindingController() {
  this.$onChanges(changes) {
    if (changes.number && changes.number.currentValue) {
        this.number = parseInt(changes.number.currentValue)
    }
  }

  this.test = function() {
    this.typeofNumber = typeof this.number // evaluates to 'number'
    this.simpleAdd = this.number + 5 // evaluates to 7 (assuming this.number was 2)
  }
}

Upvotes: 1

Prinay Panday
Prinay Panday

Reputation: 226

Passing number with '@' will always pass it as a string. If you want the object value pass number with '=' instead in the components bindings.

So:

var IntegerBindingComponent = {
  controller: IntegerBindingController,
  bindings: {
   string: '@',
   number: '=',
   numberOneWay: '<'
 },
 template: _template
}

A decent explanation can be found here: http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/

or here: Need some examples of binding attributes in custom AngularJS tags

"The '=' notation basically provides a mechanism for passing an object into your directive. It always pulls this from the parent scope of the directive..."

Upvotes: 3

Related Questions