Monday, March 4, 2013

AngularJs: One Modal Many Controllers

I started seeing a common pattern in my app for adding a new xml node to a page.  I’m tired of copy and pasting the html for a modal where the only change is two small pieces of text.
Problem: only one ng-view can be on a page. Where to put ng-controller’s?    Nesting all the controllers around ng-view is not a good idea.
Solution:  ng-template to the rescue.  Be sure to update $routeProvider to include the route. If you use this route, don’t include the controller in the route.

We don’t have to use ng-template, but then we would have to create a whole new file with just two lines of code!
The script tag below is embedded inside <div ng-app>. 

<script type="text/ng-template" id="addTask.html">
<div ng-controller="newTaskCtrl" class="form-inline">
<div ng-include src="'genericAddItemModal.html'"></div>
</div>
</script>



I’ve even gone so for as to include another  <div ng-include src=”protoXmlFile”></div> where the protoXmlFile name is set in the controller with all my variables.


This can be further simplified by using the routeProvider by calling the same template , but different controller.  Then you don’t even need to use the script template method shown above. 


$routeProvider.when('/addCoi/:className', { templateUrl: 'addListModal.html', controller: addCoiCtrl });

Don’t forget the extra quotes on ng-include

On little thing that can be tough to remember when working with ng-include. 

Works:
<div ng-include src="'tasksPrototype.xml'"></div>
Does Not Work
<div ng-include src="tasksPrototype.xml"></div>



 

AngularJS and Xml with Namespaces Manipulation

 

The code below (find.find) gave me the same ID for each task.  Not really what I wanted.

Also notice the ‘\\:’ , this is a quick fix for working with namespaces in a document.  Technically it’s not accurate since it totally bypasses checking the resolver to ensure the prefix really matches the namespace requested. But for most circumstances should work.

Below is the xml fragment we are looking for

<f:task><f:id>12345</f:id></f:task>


xmlDom.find("f\\:task").find("f\\:id").text(getId());

By moving to a loop, each item has a new id.  Not a big fan of loops, but they are fast and well supported. I like Christian Johansen’s use of the map function to do this kind of work.  Unfortunately map is not supported by all browsers.  Not enough time tonight to find a substitute.

var taskList = xmlDom.find("f\\:task");
for (var k = 0; k < taskList.length; k++)
var id = angular.element(taskList[k]).find("f:\\id");
id.text(getId());
}

Wednesday, February 27, 2013

AngularJs and Xml

Scenario: using an xml database, need to make a list of documents for user to select to edit.  This info is in the database as xml.

Problem: When converting xml to json on the server… single items are not arrays, more than one item is an array.  Array items need to be an array even if there is only one item. 

Solution: convert client side with https://code.google.com/p/x2js/ 

When x2js converts xml to Json, it provides both an array format or a single item format for elements that could be either. 

Oh! Namespace support!  That made my day!  It was even done in an elegant manner.  Namespaces stay out of the way till you get down to work on the text element!

I was expecting the JSON to be  f.rows.f.row.f.name

but no, it was so much better -  rows.row.name.__text

for the namespace – rows.row.name.__prefix

I found this on http://rabidgadfly.com/2013/02/ I’m glad he created this post a week before I needed it.

Mad style points for Glenn for use of http://plnkr.co and for the Guitar legends xml data set!

Tuesday, February 26, 2013

Directives, Buttons, and Directives

For the most part, this is considered a bad-dog thing to do in AngularJs.  But sometimes… it just has to be done.  I came across this after hours and hours of fighting, then I looked deeper into ng-view.  If the directive tag was in a different file loaded in via the view, it will render properly.

Scenario:

Main page and a button.  The button opens a modal with a form.  When the form is submitted, that data is used to make a new directive DOM element on the main page. 

Problem: 

The new instance of the directive is just string on a page.  The directive never get applied.  We want the div on 8888 to say ‘Hello World!.  Without this $compile function, we would see <div>Hello World</div>.  The directive is never applied.

  <div ng-app="poc">
<div ng-controller="mainCtrl">
<div>Test 1 : sanity check</div>
<div xrx-hello-world></div>
<div>Test 2 : applied using getElementById(8888)</div>
<div id="8888">Replace Me</div>
<div xrx-add-button=""></div>
</div>
</div>


  
 
var poc = angular.module('poc', ['ngResource', 'ngSanitize']);

poc.directive("xrxHelloWorld", function () {
return {
priority: 50,
restrict: 'A',
replace: false,
transclude: true,
scope: false,
template: '<div>Hello World</div><div ng-transclude></div>',
};
});

poc.directive('xrxAddButton', function ($compile) {
return {
priority: 50,
restrict: 'A',
replace: false,
transclude: true,
scope: false,
template: '<button>Click</button><div ng-transclude></div>',
link: function (scope, element, attr) {
var btn = angular.element(element.children()[0]);

var handleClick = function () {
var directiveStr = '<div xrx-hello-world></div>';
var directiveDom = angular.element(directiveStr);
var newDomHome = angular.element($('#8888')).html(directiveDom);
$compile(newDomHome);
};
btn.bind('click', handleClick);
}
};
});







Thursday, February 21, 2013

AngularJS ng-click button click notes

Video Link

The presenter in the video nails it when they say 'Extreme Separation' of concerns.  I love this separation, but when prototyping... it makes you think.  Times that by 10 when you have chained directives!

I do think that it's more Angular-esque to use ng-click.

This example shows ng-click with a directive. http://jsfiddle.net/V7Kpb/12/


Quick show hide box
<div class="btn btn-info" ng-model="showSummary"
       ng-click="showSummary = 2/showSummary" 
       ng-init="showSummary=0">
  Show Summary
</div>
<div class="well well-small" ng-show="showSummary">My Text Here</div>



Wednesday, February 20, 2013

Angular Notes for the day

Found a good resource today AngularJs Cheetsheet.  They hid it on the home page of the google group for AngularJs.

Painful lesson earlier this week.  Don't forget the 'ng-transclude' attribute in the HTML for your template!

Nice sample for calling controller methods in html with angular expression on jsFiddle.


<span ng-class="cssActiveIf(folder)">
        <a href="javascript:void(0)">{{folder.name}}</a>
  </span>

function AssetCtrl($scope) {

 $scope.cssActiveIf = function(item) {
        return (item === $scope.selection.currentFolder) ? "active" : "";
    };
}