Sunder
Sunder

Reputation: 503

Angular exception : attempt to use a dehydrated detector

After looking at several topics discussing this error, I can't find any reason for my code to produce EXCEPTION: Attempt to use a dehydrated detector: PortsInputComponent_1 -> valueChange. I don't think the stacktrace is usefull, since it is only angular code, and not mine.

I've looked at those posts : Angular2 EXCEPTION: Attempt to detect changes on a dehydrated detector, EXCEPTION: Attempt to detect changes on a dehydrated detector, What is a dehydrated detector and how am I using one here?, and at this github issue https://github.com/angular/angular/issues/6786.

They all seem to be using some asynchronous operations, which I'm not, and none of those solutions fit my project. Please don't close it as duplicate.

Basically what I'm trying to do is a special input for multiple ports. I want to always have a blank input, so the user don't have to press a button in order to add a new one. I don't want to have more than one blank input though, so I need to remove them when the user deletes the last character. The demo below does this perfectly.

Here is the code inside the plunker :

import { Component, Input }             from 'angular2/core';

@Component({
  selector: 'my-ports-input',
  template:`
<div layout-gt-sm="row" layout-wrap>

  <md-input-container class="md-block" flex-gt-sm
      *ngFor="#port of values() ; #i = index ;">
    <label>Port</label>
    <input md-input class="ports-input" type="text" size="6"
        [value]="port.title" (input)="changeValueAtIndex(i, $event)" />
  </md-input-container>
</div>
`
})

export class PortsInputComponent {
  // More complex model that contains an array of string values
  @Input() attribute: {value : string[]}
  strings = []

  changeValueAtIndex(index, event) {
    // Case where we changed the value of the latest port : we add a new input
    if (!this.attribute.value[index]) {
      this.strings.push({ title: '' })
    }

    this.attribute.value[index] = event.target.value

    if (event.target.value.length === 0) {
      this.attribute.value.splice(index, 1)
      this.strings = [] // Should reload the array, but also causes the issue below
    }
  }

  // Use this function that returns an array of objects instead of an array of string.
  // Using directly attribute.value (array of string) cause this error:
  // https://github.com/angular/angular/issues/6786
  //
  // Returning directly this.attribute.value.map((value) => { return {title: value} })
  // causes an infinite loop of error... for some reason
  // So use an intermediate variable instead
  values() {
    if (!this.strings.length) {
      let values: string[] = this.attribute.value
      this.strings = values.map((value) => { return {title: value} })
      this.strings.push({ title: '' })
    }
    return this.strings
    // return this.attribute.value.map((value) => { return {title: value} })
  }
}

Does anyone understands why this error is thrown in my case ?

I wanted to reproduce this error in a plunker, but unfortunately it doesn't cause any exception, the only difference I see between my app and the plunker is the attribute variable. In my app it is a model and not a JSON object, could it change something ?

Upvotes: 1

Views: 379

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657731

Delaying this code a bit might be able to work around (not tested because I can't reproduce)

  changeValueAtIndex(index, event) {
    setTimeout(() => {
      // Case where we changed the value of the latest port : we add a new input
      if (!this.attribute.value[index]) {
        this.strings.push({ title: '' })
      }

      this.attribute.value[index] = event.target.value

      if (event.target.value.length === 0) {
        this.attribute.value.splice(index, 1)
        this.strings = [] // Should reload the array, but also causes the issue below
      }
    },0});
  }

Upvotes: 1

Related Questions