angularjs-styleguide icon indicating copy to clipboard operation
angularjs-styleguide copied to clipboard

Parent component trigger function in child component

Open CarlosOV opened this issue 7 years ago • 5 comments

I have a camera-component inside a parent-component. I want a make to snapshop from parent, but I can not find a way to do it.

CarlosOV avatar Mar 28 '17 21:03 CarlosOV

I have the same issue with a child component

fredyrsam avatar Mar 29 '17 15:03 fredyrsam

I'm a little confused on the goal there, but you could leverage one-way bindings to traverse data into the child component, without mutating the parent scope.

danielgeri avatar Mar 29 '17 20:03 danielgeri

can you give me an example how to solve it using one-way bindings?

CarlosOV avatar Mar 29 '17 21:03 CarlosOV

ah i think i misunderstood your question. To rephrase, you have a child component that is responsible for taking a picture that needs to be triggered by the parent component. Is this correct? If so, one way of doing it is the following: camera.component.js

class CameraController {
  constructor(CameraService) {
    this._cameraService = CameraService;
  }

  $onChanges(changes) {
    if (changes.buttonPressed.currentValue) {
      this._takePicture();
    }
  }

  _takePicture() {
    this._cameraService
      .takePicture()
      .then(() => /* some code */)
      .catch(err => /* handle err */)
      .finally(() => this.resetButton());
  }

}

export default Camera {
  template: require('./camera.html'),
  controller: CameraController,
  controllerAs: 'vm',
  bindings: {
    buttonPressed: '<',
    resetButton: '&'
  }
};

parent.component.js

class ParentController {
  takePicture() {
    this.buttonPressed = true;
  }

  resetButton() {
    this.buttonPressed = false;
  }
}

export default Parent {
  template: require('./parent.html'),
  controller: ParentController,
  controllerAs: 'vm'
};

parent.html

<div>
  <camera-component
    button-pressed="vm.buttonPressed"
    reset-button="vm.resetButton()"
  />
  <button ng-click="vm.takePicture()">Say Cheeze</button>
</div>

also - confused on why the trigger can't exist within the child component

danielgeri avatar Mar 29 '17 21:03 danielgeri

In order to decouple the parent from child further, would this approach be considered in good style?

class CameraController {
  constructor(CameraService) {
    this._cameraService = CameraService;
  }

  $onChanges(changes) {
    if (changes.buttonPressed.currentValue) {
      this._takePicture();
    }
  }

  _takePicture() {
    this._cameraService
      .takePicture()
      .then(() => /* some code */)
      .catch(err => /* handle err */);
  }
}

export default Camera {
  template: require('./camera.html'),
  controller: CameraController,
  controllerAs: 'vm',
  bindings: {
    buttonPressed: '<',
  }
};

parent.component.js

class ParentController {
  constructor($timeout) {
    this.$timeout = $timeout;
    this._buttonPressed = false;
  }

  get buttonPressed() {
    return _buttonPressed;
  }

  set buttonPressed(value) {
    const { $timeout } = this;
		
    $timeout(() => {
      this._buttonPressed = value;

      if (this._buttonPressed) {
        $timeout(() => {
          this._buttonPressed = false;
        });
      }
    });
  }
	
  takePicture() {
    this.buttonPressed = true;
  }
}

ParentController.$inject = ['$timeout'];

export default Parent {
  template: require('./parent.html'),
  controller: ParentController,
  controllerAs: 'vm'
};

parent.html

<div>
  <camera-component button-pressed="vm.buttonPressed" />
  <button ng-click="vm.takePicture()">Say Cheeze</button>
</div>

Ultimately, we leave the resetting of the buttonPressed property to the parent controller. This still triggers the change in the child and now the child does not care about manipulating the state of its parent.

ghost avatar Apr 04 '19 15:04 ghost