简体   繁体   English

Angular 1.5+中Component的DOM操作

[英]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. 我想在该下拉列表上触发ng-change事件时显示/隐藏UI元素。

This is the plunkr link to my code. 这是我的代码的plunkr链接。

The 'onCarChange()' method is getting called but the UI elements are not being hidden or shown based on the selection. 调用'onCarChange()'方法,但不会根据选择隐藏或显示UI元素。

I am still learning AngularJS, so if I am taking a wrong approach then kindly let me know. 我还在学习AngularJS,所以如果我采取了错误的方法,那么请告诉我。

HTML markup HTML标记

<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 AngularJS代码

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 选择-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

scope for components is always isolate. 组件的范围始终是隔离的。 you have two options. 你有两个选择。 option one is to use a directive instead. 选项一是使用指令代替。 ( plunkr ) 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 (eg car) into the component and use events for changing the dropdown, but you got the point. plunkr )请注意,最好将类似模型(例如汽车)的东西传递到组件中并使用事件来更改下拉列表,但是你明白了。

1) define controller on outer scope and pass it into component 1)在外部范围上定义控制器并将其传递给组件

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

2) bind value to isolate scope of component 2)绑定值以隔离组件的范围

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

3) adjust template 3)调整模板

<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>

Here is my refactor for your code 这是我的代码重构

PLUNKER CODE PLUNKER代码

index.html 的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 car.module.js //作为主要

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 选择-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 selectCar.directive.js //必须变为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'
    });

The component you've created should be seen as an isolated component. 您创建的组件应被视为一个独立的组件。 Therefor the vm.showDataGrid and vm.disableRunButton are not accessible outside the component template. 因此,组件模板外部无法访问vm.showDataGridvm.disableRunButton

If this is desired, you can do two things: 如果需要,您可以做两件事:

  1. Make the selection an event 选择是一个事件
  2. Make the component use ngModel so it can be viewed as a form control that emits a value. 使组件使用ngModel,以便可以将其视为发出值的表单控件。

I tend to favor the second approach. 我倾向于采用第二种方法。 See this plunkr for an implementation: https://plnkr.co/edit/RG51ADtvHuRSJDUMv6mV?p=preview 请参阅此plunkr了解实现: https ://plnkr.co/edit/RG51ADtvHuRSJDUMv6mV?p = preview

The core is in the new implementation of the CarsController: 核心是在CarsController的新实现中:

function CarsController() {

}

CarsController.prototype.onCarChange = function() {
  // Because of the ng-model on the <select>, this.myCars.selectedCar is already
  // up to date.
  this.ngModel.$setViewValue(this.myCars.selectedCar);
}


CarsController.prototype.$onInit = function() {
  var vm = this;

  vm.ngModel.$render = function() {
   // This is called when the bound model value changes from external sources
    // vm.ngModel.$modelValue contains the new value, it may be a completely different
    // object, so set the selected to the one in the options
    vm.myCars.selectedCar = vm.myCars.options.find(function(item) {
      return vm.ngModel.$modelValue && item.id == vm.ngModel.$modelValue.id;
    });
  }



  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' }
  };
  // Initialize the ngModel value
  this.onCarChange();
}

Then you can simply use ng-model on your new component from html: 然后你可以简单地在html的新组件上使用ng-model:

<select-car ng-model="selectedCar"></select-car>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM