Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DOM Manipulation from Component in Angular 1.5+

I have created a custom directive for dropdown. I want to show/hide UI elements when the ng-change event is fired on that dropdown.

This is the plunkr link to my code.

The 'onCarChange()' method is getting called but the UI elements are not being hidden or shown based on the selection.

I am still learning AngularJS, so if I am taking a wrong approach then kindly let me know.

HTML markup

<div ng-app="RedBlack">
    <select-car></select-car> <-- element directive
    <p ng-show="vm.showDataGrid">DATA GRID</p>
    <button ng-show="!vm.disableRunButton">Run Button</button>
</div>

AngularJS code

angular
    .module('RedBlack', [])
    .component('selectCar', {
      restrict: 'E',
      templateUrl: 'select-car.html',
      bindings: {

      },
      transclude: true,
      controller: CarsController,
      controllerAs: 'vm',
      replace: true
    })
    .controller("CarsController", CarsController);

function CarsController() {
  var vm = this;      
  vm.showDataGrid = true;
  vm.disableRunButton = true;
  vm.myCars = {
    options: [
      { id: '1', name: 'LaFerrari' },
      { id: '2', name: 'Porsche 918' },
      { id: '3', name: 'McLaren P1' }
    ],
    selectedCar: { id: '2', name: 'Porsche 918' }
  };      
  vm.onCarChange = onCarChange;

  function onCarChange() {
    console.log("Called onCarChange()");
    vm.showDataGrid = false;
    vm.disableRunButton = false;
    return true;
  }

}

select-car.html

<div>
  <select class="form-control" ng-options="option.name for option in vm.myCars.options track by option.id"
  ng-model="vm.myCars.selectedCar"
  ng-change="vm.onCarChange()">
  </select>
</div
like image 495
overlord Avatar asked Apr 26 '26 10:04

overlord


2 Answers

scope for components is always isolate. you have two options. option one is to use a directive instead. (plunkr)

angular
  .module('RedBlack.components', [])
  .directive('selectCar', function() {
    return {
      restrict: 'E',
      templateUrl: 'select-car.html',
      transclude: true,
      controller: CarsController,
      controllerAs: 'vm'
    };
  });

If you want to use a component one option is to pass the value into it. (plunkr) Notice it would be better to pass something like a model (e.g. car) into the component and use events for changing the dropdown, but you got the point.

1) define controller on outer scope and pass it into component

<html ng-app="RedBlack" ng-controller="CarsController as vm">
    ...
    <select-car parent="vm"></select-car>
    ...
</html>

2) bind value to isolate scope of component

angular
  .module('RedBlack.components', [])
  .component('selectCar', {
    restrict: 'E',
    templateUrl: 'select-car.html',
    bindings: { parent: "=" }, // = means two way data binding
    controllerAs: "vm"
  });

3) adjust template

<div>
  <select class="form-control" ng-options="option.name for option in vm.parent.myCars.options track by option.id"
  ng-model="vm.parent.myCars.selectedCar"
  ng-change="vm.parent.onCarChange()">
  </select>
</div>
like image 140
oshell Avatar answered Apr 28 '26 01:04

oshell


Here is my refactor for your code

PLUNKER CODE

index.html

<!DOCTYPE html>
<html ng-app="RedBlack">

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
    <script src="car.module.js"></script>
    <script src="selectCar.directive.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <div id="app" ng-controller='MainController as vm'>
    <h1>Hello a car!</h1>
    <select-car 
      on-car-changed='vm.carChange(car)'>
    </select-car>

    <p ng-show="!vm.showDataGrid">DATA GRID</p>

    <p>{{ vm.selected.name }}</p>

    <button ng-show="!vm.disableRunButton">Run Button</button>
    </div>
  </body>

</html>

car.module.js //as main

angular
  .module('RedBlack.cars', [])
  .controller("MainController", MainController);

function MainController() {

  var vm = this;

  vm.showDataGrid = true;
  vm.disableRunButton = true;

  vm.carChange = carChange;

  function carChange(car) {

    console.log("Called onCarChange()");
    console.log(car)

    vm.selected = car.name
    vm.showDataGrid = false;
    vm.disableRunButton = false;
  }

}

component

select-car.html

<div>
  <select 
    class="form-control" 
    ng-options="item as item.name for item in vm.myCars track by item.id"
    ng-model="vm.selected"
    ng-change="vm.onCarChanged({car: vm.selected})">
  </select>
</div>

selectCar.directive.js // must become as select-car.component.js

  angular
    .module('RedBlack.components', [])
    .component('selectCar', {
      templateUrl: 'select-car.html',
      bindings: {
        onCarChanged: '&'
      },
      controller: [function() {
        var vm = this;

          vm.myCars = [
              { id: 1, name: 'LaFerrari' },
              { id: 2, name: 'Porsche 918' },
              { id: 3, name: 'McLaren P1' }
          ];

          vm.selected = vm.myCars[0]
      }],
      controllerAs: 'vm'
    });
like image 42
Yuriy Yakovenko Avatar answered Apr 28 '26 01:04

Yuriy Yakovenko