简体   繁体   中英

How to dynamically generate DOM with Angular.js?

I'm getting started with Angular.js and I'm wondering how to do something along the lines of this (pseudocode):

<li ng-repeat="item in items">
    <# if(item.dataType == "string") { #>
        <input type="text" />
    <# } else if(...) { #>
        <input type="password" />
    <# } #>
</li>

I know the above code is not angularish, and I know that for simple processing I could use a conditional ng-hide or ng-show or something similar. But for complex behavior, if I had to perform various data checks and business logic, how could I dynamically generate DOM elements with Angular.js?

Within the angular world, DOM manipulation is accomplished using angularjs directives. Here is the angular documentation on directives: https://docs.angularjs.org/guide/directive , you would do well to read through this.

Here is some sample code that will accomplish the idea of your psuedo code:

var myApp = angular.module('myApp', []);

myApp.controller('MyController', function ($scope){
  $scope.items = [
    42, "hello, world!", 3.14, "i'm alive!"
    ]
});

myApp.directive('myInputDirective', function () {
  return {
    restrict: 'E',
    replace: true,
    template: '<div></div>',
    link: function (scope, element, attrs) {
      if (typeof scope.current === "string") {
        element.append('<input type="text">');
      } else {
        element.append('<input type="password">');
      }
    }
  }
});

and here's how the html would look:

<div ng-controller="MyController">
  <ul ng-repeat="item in items" ng-init="current = item">
    <my-input-directive></my-input-directive>
  </ul>
</div>

Here is a plnkr with the working example: http://plnkr.co/edit/iiS4G2Bsfwjsl6ThNrnS?p=preview

Directives are how the DOM is manipulated in angular. First thing to notice is that angular has a set of directives that come out of the box, we're using a few above ( ng-repeat , ng-init , ng-controller ). Above we've created a custom directive that will analyze the data type of each item in the items array of our MyController controller, and append the correct html element.

I imagine that you already understand the ng-repeat directive, so I'll skip that. I'll explain what I'm doing with the ng-init directive though. The ng-init directive allows you to evaluate an expression in the current scope. What this means is that we can write an expression that is evaluated in our current controllers scope, in this case the MyController scope. I am using this directive to create an alias for our current item named current . We can use this inside our directive to check what type the current item in the array iteration is.

Our directive myInputDirective , is returning an object with a few different properties. I won't explain them all here (I'll let you read the documentation), but I will explain what the link function is and what I am doing with it. A link function is typically how we modify the DOM. The link function takes in the current scope (in this case the scope of MyController ), a jqLite wrapped element that is associated with the directive, and the attrs which is a hash object with key-value pairs of normalized attribute names and values. In our case, the important parameters are the scope , which contains our current variable, and the element , which we will append the correct input onto. In our link function, we're checking the typeof our current item from our items array, then we are appending an element onto our root element based on what the type of the current item is.

For this particular problem, what I'm doing above is overkill. But based off of your question I figured you were looking for a starting point for more advanced uses of angular apart from the built in directives that angular provides. These are somewhat advanced topics in angular, so I hope that what I've said make some sense. Check out the plunker and play around with it a bit, and go through some of the tutorials on https://docs.angularjs.org/guide . Hope this helps!

You can use ng-show to conditionally hide and show elements eg:

<input ng-show="item.dataType === 'string'" type="text"/>
<input ng-show="..." type="password"/>

Assuming your object looks like this:

$scope.items = [
  {
    dataType: 'string',
    value: 'André Pena'
  }, 
  {
    dataType: 'password',
    value: '1234'
  }, 
  {
    dataType: 'check',
    value: true
  }
];

Option #1 - ng-switch plunker

<body ng-controller="MainCtrl">
  <ul>
    <li ng-repeat="item in items">

      <div ng-switch="item.dataType">
        <div ng-switch-when="string" ><input type="text" ng-model="item.value" /></div>
        <div ng-switch-when="password" ><input type="password" ng-model="item.value" /></div>
        <div ng-switch-when="check" ><input type="checkbox" ng-model="item.value" /></div>
      </div>

    </li>
  </ul>
</body>

Option #2 - ng-show plunker

<body ng-controller="MainCtrl">
  <ul>
    <li ng-repeat="item in items">

      <div ng-show="item.dataType == 'string'" ><input type="text" ng-model="item.value" /></div>
      <div ng-show="item.dataType == 'password'" ><input type="password" ng-model="item.value" /></div>
      <div ng-show="item.dataType == 'check'" ><input type="checkbox" ng-model="item.value" /></div>

    </li>
  </ul>
</body>

Option #3 - ng-hide plunker

<body ng-controller="MainCtrl">
  <ul>
    <li ng-repeat="item in items">

      <div ng-hide="!(item.dataType == 'string')" ><input type="text" ng-model="item.value" /></div>
      <div ng-hide="!(item.dataType == 'password')" ><input type="password" ng-model="item.value" /></div>
      <div ng-hide="!(item.dataType == 'check')" ><input type="checkbox" ng-model="item.value" /></div>

    </li>
  </ul>
</body>

You should use the ng-if directive.

<input ng-if="item.dataType === 'string'" type="text"/>
<input ng-if="..." type="password"/>

The problem with using ng-show like @rob suggested, is that it only uses CSS to hide the element, which is not ideal if you want the two inputs to have the same name/ID.

ng-if will remove the element from the DOM if the condition is not true.

for a problem this simple there's no need to go and implement your own directive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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