Reputation: 59446
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?
Upvotes: 3
Views: 1252
Reputation: 34257
Assuming your object looks like this:
$scope.items = [
{
dataType: 'string',
value: 'André Pena'
},
{
dataType: 'password',
value: '1234'
},
{
dataType: 'check',
value: true
}
];
<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>
<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>
<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>
Upvotes: 1
Reputation: 2468
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!
Upvotes: 5
Reputation: 3265
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.
Upvotes: 0