First Steps
The first things first, enqueue the angular.js library:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
Using Angular for “live” page updates.
So this was my first attempt with AngularJS. I found an online tutorial and basically followed it.
First Name :
Surname :
Results
My name is: {{firstname}} {{surname}}
The code:
<div ng-app=""> <p>First Name : <br><input type="text" ng-model="firstname"></p> <p>Surname : <br><input type="text" ng-model="surname"></p> <h4>Results</h4> <h3>My name is: {{firstname}} {{surname}}</h3> </div>
Basic maths with AngularJS
So after my first encounter with AngularJS, I decided to press ahead with a little task of my own invention, well kind of. I thought adding numerical values together from form inputs has probable “real world” usage. This proved a little more taxing, as really at this point I still had a small (no) amount of knowledge regarding AngularJS.
The first issue I ran aground on was how I wanted to use the Angular library, specifically using AngularJS within a WordPress blog post as this has real world type applications for me at the time.
For my first attempt I thought having multiple “apps” loading into the content and using shortcodes would be a good idea. This I discovered is not really the way this library is strictly meant to be used, but none the less with the help of trusty StackOverflow I found a few ways to load multiple apps into a single page.
So after much playing around I found the below code to return multiple apps:
var firstApp = angular.module('firstApp', []); firstApp.controller('FirstController', function($scope) { }); var secondApp = angular.module('secondApp', []); secondApp.controller('SecondController', function($scope) { }); var apOne = document.getElementById('app-one'); var apTwo = document.getElementById('app-two'); angular.element(document).ready(function() { angular.bootstrap(apOne, ['firstApp']); angular.bootstrap(apTwo, ['secondApp']); });
One of the things I found difficult at this point was understanding how the naming convention worked inside the HTML structure so after much tutorial reading and googling I got the code below to work.
<div id="app-two"> <div ng-app="secondApp" ng-controller="SecondController"> <form name="form"> <p>First Number : <br><input name="firstnumber" type="text" ng-model="firstnumber" ng-pattern="/^\d{1,10}$/" /><br> <span class="error" ng-show="form.firstnumber.$error.pattern">Numbers only please, duh!</span> </p> <p>Second Number : <br><input name="secondnumber" type="text" ng-model="secondnumber" ng-pattern="/^\d{1,10}$/" /><br> <span class="error" ng-show="form.secondnumber.$error.pattern">Numbers only please, duh!</span> </p> <p>Math selector: <br> <select ng-model="theselector"> <option value="plus" selected="selected">Plus</option> <option value="minus">Minus</option> <option value="times">Multiply</option> <option value="div">Divide</option> </select> </p> <h4>Results</h4> <div ng-if="theselector == 'plus'"> <h3>Result: {{(firstnumber+secondnumber) || 0 | number:0}}</h3> </div> <div ng-if="theselector == 'minus'"> <h3>Result: {{(firstnumber-secondnumber) || 0 | number:0}}</h3> </div> <div ng-if="theselector == 'times'"> <h3>Result: {{(firstnumber*secondnumber) || 0 | number:0}}</h3> </div> <div ng-if="theselector == 'div'"> <h3>Result: {{(firstnumber/secondnumber) || 0 | number:4}}</h3> </div> </form> </div> </div>
I used a get_template_part() within a shortcode to get this into the blog post.
While the above worked I could not get the input to only allow numerical values to be exclusively allowed in the input fields, when using type=”number” so having seen reference to the “ng-pattern” directive I added this to the input field. While partially successful the best I could manage was an error warning if none numerical characters were typed into the input field.
After reading through many tutorials and general AngularJS documentation I decided a more single app approach was better and switched to having a single app declared in the blog post content area. I choose to go down the WordPress is_caterory() road so any further AngularJS articles would enqueue the required scripts.
As I wanted only numbers to be allowed in the input fields, I found most folks were opting for declaring a “directive” to achieve this.
What is a directive: Directives are properties on a DOM element that tell AngularJS to attach a specified behaviour to that DOM element or even transform the DOM element and its children. So it has the effect of extending the HTML.
So the code as it stood after I made the above changes:
var BlogApp = angular.module('blogApp', []); BlogApp.controller('blogCtrl', function($scope) { }); BlogApp.directive('numericonly', function () { return { require: 'ngModel', link: function (scope, element, attr, ngModelCtrl) { function fromUser(text) { var transformedInput = text.replace(/[^0-9]/g, ''); if (transformedInput !== text) { ngModelCtrl.$setViewValue(transformedInput); ngModelCtrl.$render(); } return transformedInput; } ngModelCtrl.$parsers.push(fromUser); } }; });
And the HTML:
<form name="form"> <p>First Number : <br><input name="firstNumber" type="text" ng-model="firstNumber" ng-pattern="/^\d{1,10}$/" numericonly /><br> <span class="error" ng-show="form.firstNumber.$error.pattern">Numbers only please, duh!</span></p> <p>Second Number : <br><input name="secondNumber" type="text" ng-model="secondNumber" ng-pattern="/^\d{1,10}$/" numericonly /><br> <span class="error" ng-show="form.secondNumber.$error.pattern">Numbers only please, duh!</span> </p> <p>Math selector: <br> <select ng-model="theSelector"> <option value="plus" selected="selected">Plus</option> <option value="minus">Minus</option> <option value="times">Multiply</option> <option value="div">Divide</option> </select> </p> <h4>Results</h4> <div ng-if="theSelector == 'plus'"> <h3>Result: {{(firstNumber-0) + (secondNumber-0) || 0 | number:0}}</h3> </div> <div ng-if="theSelector == 'minus'"> <h3>Result: {{(firstNumber - secondNumber) || 0 | number:0}}</h3> </div> <div ng-if="theSelector == 'times'"> <h3>Result: {{(firstNumber * secondNumber) || 0 | number:0}}</h3> </div> <div ng-if="theSelector == 'div'"> <h3>Result: {{(firstNumber / secondNumber) || 0 | number:4}}</h3> </div> </form>
Note the -0 added after the models in the adding part of the if condition. This has the effect of casting the models to an int, I used this because when adding numbers Angular was not seeing number and treating using “+” to concatenate the to numbers as a string.
So my extremely crude calculator now looks like this:
An issue I discovered along the way.
I found that AngularJS was executing the code within the <pre> tags I am using to display the code on this site. After trying various methods to remove the binding from the pre tags, I had to make some small changes to the tinyMCE editor to allow me to add Angular directives to the <pre> tag without the editor removing the code on update.
I added this to my functions.php:
function unit_override_mce_options($initArray) { $opts = '*[*]'; $initArray['valid_elements'] = $opts; $initArray['extended_valid_elements'] = $opts; return $initArray; } add_filter('tiny_mce_before_init', 'unit_override_mce_options');
Then added this directive to the pre tags: “ng-non-bindable”.
So this was my first day with AngularJS, I will be having a go at some more difficult apps with AngularJS but this is what I achieved on my first go. More posts on angular can be for here.