Adding Angular Markup to a Genesis Child Theme (Part 1)

This is the secondĀ post in a three part series on using Genesis and Angular. Part 2 can be read here, and Part 3 can be read here.Ā 

This month is Angular August, and so I’ve been focusing on learning Angular (1, not 2Ā yet… but soon!).Ā I’ve set myself several tasksĀ learning angular, one of which is developing a starter Genesis child theme using Angular and Gulp (since I’ve been wanting to check out and use Gulp more too… I still love you, Grunt). HereĀ is what I’m trying to do with this project:

Primary objective:Ā Create a view area that will display all the contents of posts and pages without a page reload usingĀ Genesis and Angular.

Do this by:

  1. Adding markup to my Genesis child theme
  2. Fetching data with the WP REST API and Angular
  3. Routing the data with Angular on posts and pages

If you’ve used Angular, you know you need to specify ng-appĀ and ng-viewĀ in your html markup so that your Angular app will run.Ā This is easy to do with a starter theme like _’s, but if you’re building on top of a framework like Genesis, you need to use the available hooks and filtersĀ to manage your markup.

I’m a part of the community at WP Developer Club and KnowtheCode.io, and Tonya does a great job walking through the markup.phpĀ file and structure in Genesis. Check it out and join up if you’re thirsty for knowledge!

So, here’s how I finally landed on the markup I needed to be able to addĀ the basic Angular directives to my Genesis Markup…

(Note:Ā Unless otherwise noted, all PHP goes in the function.phpĀ file and all JavaScript has been enqueued from a main.js file)

Adding Directives andĀ Properties with Values to Attributes

With Angular, there are several directives you need to place in your HTML for an app to work, or in this case, for a Genesis child theme to assume an app-like state. This include:

  • ng-app
  • ng-repeat
  • ng-model
  • ng-whatever…….

No big deal if you’re working with straight HTML or a custom theme, but for frameworks, you need to filter the markup already included and running in your parent theme. In this particular case,Ā I needĀ toĀ be able to add this like ng-app, ng-controller, ng-view, etc. to things like <head>, <main>, or any other element already provided by Genesis.

Let’s start with the easy stuff… adding ng-appĀ to our project.

In many Angular tutorials (and maybe even the documentation), you will find that you’re typically adding Angualr to the <html>Ā tag, as in <html ng-app = "myApp">. This increases the scope of the Angular app to the entire HTML document. This great, but since I only need it on the front end (for now!), I’m just going to add it to the <body>Ā tag:

Adding ng-app to body tag

In order to filter and add these directives (or any property), we’re going to use the provided filter genesis_attr_body. Actually, if you’re using Kint, you can check and see all the functions firing on that filterĀ this:

add_action( 'genesis_loop', __NAMESPACE__ . 'check_body_class_filters'  );

function check_body_class_filters() {
   global $wp_filter;
   d($wp_filter['genesis_attr_body']);
}

If you’re running the Genesis Sample child theme, you’ll probably get a result like this:

getting the filters for the body

Great! So, we just need to use a simple filter to add on our directive, like this:

add_filter( 'genesis_attr_body', __NAMESPACE__ . 'add_ng_app_to_body' );

function add_ng_app_to_body( $attributes ) {
   
   $attributes['ng-app'] = 'myApp';
   
   return $attributes;
}

And BOOM! ng-appĀ is now in our body tag:

ng-App is now in our body tag

Excellent! You can use the same technique to add controllers like ng-controller, ng-repeat, etc. where you need.

This means we can and should now add a view… But how??…

Adding Directives with No Values (i.e. ng-view)

The process is very similar, except that we want to add only ng-viewĀ withĀ no value, instead of what we just did. The result we’re looking for is something like <div ng-view>, not <div ng-view="myView">. So, how do we accomplish this?

At first, I thought, “Just do the same thing as before, but instead run: $attributes['ng-app'] = '' or null. However, this does not return as part of the array, and you don’t get anything in there.

Instead, we need to use the genesis_attr_{context}_output filter. This returns a string of the outputĀ which we can then filter and return. In my case, I want to filter the <main class="content">Ā element string. So, I did this to concatenate on the string:

//*Add the ng-view to the <main class="content" element
add_filter( 'genesis_attr_content_output', 'add_ng_view_to_content', 99, 3 );

function add_ng_view_to_content( $output ) {
$output .= ' ng-view';
return $output;
}

After adding this filter, we get the output we need to add the view to this HTML element:

adding ng-view to the main element

Awesome! Moving right along.

You might be wondering, “Why are we adding ng-viewĀ to the <main>Ā tag??” Great questions! For now,Ā I wantĀ the <main>Ā element to be the part that changes when rendering pages and posts. Genesis will use this element tag no matter the layout (full-width, content-sidebar, sidebar-content, etc.), so I want this to be the element that is updated by Angular.

Does it work??

Let’s find out…

If you haven’t already, jump over and check out Josh Pollock’s article on Torque Mag: The Basics of AngularJS with the WordPress REST API.

Thinking along the lines of Josh’s code, how can we get this to work? Simple. First we want to removeĀ default loop from Genesis (on all pages, for the sake of this example, quick and dirty). Then, we want to output some basic HTML with a controllerĀ and some bindings to test. This is all pretty easy to do:

//*Remove Standard Genesis Loop
remove_action('genesis_loop', 'genesis_do_loop');

//*Add a controller in the Angular view to work with
add_action('genesis_loop', __NAMESPACE__ . 'do_ng_view_content');
function do_ng_view_content() {
$output = '<div ng-controller="example">
<form>
<input type="text" ng-model="post.placeholder" />
</form>
<div>{{post.placeholder}}</div>
</div>';
echo $output;
}

Next, we want to make sure we’ve got the Angualar app up and running in an enqueued JavaScript file, like so:

'use-strict';

angular.module('myApp', [])
.controller('example', ['$scope', function ($scope) {
$scope.post = {
placeholder: 'Enter Text'
};
}]);

The result?:

Angular app in Genesis1

So, you can see we have our app, controller, and the bindings are updating. This is exactly what we want!

I’ll be using the WP REST API to dynamically update posts and pages when clicked and share that inĀ another post. For now, this should get you (and me!) started:-).

 

Check out this series of videos Markup and Wraps in GenesisĀ from Tonya at KnowtheCode.