Starting with AngularJS

Written by: John | 18th Oct 2019

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:

First Number :

Numbers only please, duh!

Second Number :

Numbers only please, duh!

Math selector:

Results

Result: {{(firstNumber-0) + (secondNumber-0) || 0 | number:0}}

Result: {{(firstNumber - secondNumber) || 0 | number:0}}

Result: {{(firstNumber * secondNumber) || 0 | number:0}}

Result: {{(firstNumber / secondNumber) || 0 | number:4}}

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.

Recent Posts

Code

Swipe close for mobile menu

Using Vanilla JS (ish) to add swipe features to mobile views.
WordPress

Wordpress White Label Development

Digital Agencies selling WordPress as a solution need to be experts in the WordPress CMS, but they don't need to do the actual coding of the websites themselves to excel & prosper.
Code

Full Width YouTube Videos

Make YouTube videos take the full width of an element while retaining the 16:9 ratio.
Code

CSS Transitions

Easy copy and paste transition css, to enable transitions to all properties.
Web Build

Set Up Sage 8.5 + Git for localhost

Set up Roots Sage on your local host for WordPress development. Open a Terminal and follow the steps below: Step 1: Set up Bit Bucket Step 2: Init Git locally cd /path/to/your/project git init git remote add origin https://your-account@bitbucket.org/your-instance/project-name.git  …