Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs - Dynamically change dom with directives or widgets?

my goal is to understand how to use angularJS correctly. I want to be able to tie a selection of variable to dynamically changing the DOM structure using angularJS. I dont think I'm quite understanding the documentation that angular provides and I haven't found any examples here or otherwise. Any help is appreciated.

The idea is that I have this use case where I first start with the selection of the type and from that type selected, the appropriate input type elements will be created and then recorded later with the ng-model (from textareas to checkboxes for example), all the while controlled by the angularjs controller for validation/restrictions. I'm used to the idea of having clone-able elements on the page and destroying and creating new with jQuery, but I've been reading that controllers should not have this logic and should instead be created with directives/widgets. I dont see any examples of directives or widgets being manipulated in this way however so I'm not even sure how to proceed. Can I use directives to manipulate the DOM in this way, not just once but multiple times based on a watched element?

Example of what I would like to do.

$scope.types = ['Type1','Type2']

// something along the lines of...
$scope.layouts = {'Type1':['textarea','textarea'], 'Type2':['numeric','datepicker']}

Select Type 1:

  • Show 2 text areas

Select Type 2:

  • Show a numeric input
  • Show a date picker
like image 963
kman Avatar asked Aug 07 '12 20:08

kman


2 Answers

This is how I would do it. Note that this is a just a starting point. There is still a matter of binding to particular values in the corresponding inputs. I hope it helps.

Markup:

<html ng-app="App" ng-controller="MainCtrl">

<body>

  <component index="0"></component>
  <component index="1"></component>
  Current type: {{type}}
  <button ng-click="toggleType()">Toggle</button>

</body>

</html>

Directive:

var ngApp = angular.module('App', []).directive('component', function() {
  var link = function(scope, element, attrs) {
    var render = function() {
      var t = scope.layouts[scope.type][attrs.index];
      if (t === 'textarea') {
        element.html('<' + t + ' /><br>');
      }
      else {
        element.html('<input type="' + t + '"><br>');
      }
    };
    //key point here to watch for changes of the type property
    scope.$watch('type', function(newValue, oldValue) {
      render();
    });

    render();
  };
  return {
    restrict : 'E',
    link : link
  }
});

Controller:

var MainCtrl = function MainCtrl($scope) {
  $scope.type = 'Type1';
  $scope.types = [ 'Type1', 'Type2' ];
  $scope.layouts = {
    'Type1' : [ 'textarea', 'textarea' ],
    'Type2' : [ 'number', 'text' ]
  };

  $scope.toggleType = function() {
    if ($scope.type === 'Type1') {
      $scope.type = 'Type2';
    }
    else {
      $scope.type = 'Type1';
    }
  };
};
like image 187
Liviu T. Avatar answered Nov 06 '22 01:11

Liviu T.


The most drop dead easy way I can think of doing this is by just using ng-show and ng-hide.

http://jsfiddle.net/cfchase/Xn7PA/

<select ng-model="selected_type" ng-options="t for t in types">
</select>

<div ng-show="selected_type=='Type1'">
    <input type="text" id="text1" ng-model="text1"/>
    <input type="text" id="text2" ng-model="text2"/>
</div>

<div ng-show="selected_type=='Type2'">
    <input type="number" id="numeric1" ng-model="numeric1"/>
    <input type="date" id="date1" ng-model="date1"/>
</div>

Of course you could clean this up without putting any logic in the html, but I didn't want to cloud the issue with extra stuff in the controller.

For validation, refer to the forms documentation. It's likely you will use mostly the AngularJS built in validation with some custom ones you build.

As for directives, the online docs are dense, but it will click after you've experimented for awhile. For a gentler introduction, Jon Lindquist has a hello world tutorial on YouTube. Directives are definitely the way to do DOM manipulation in Angular.

like image 4
Chris Avatar answered Nov 06 '22 00:11

Chris