-
Notifications
You must be signed in to change notification settings - Fork 47
AngularJS 101
AngularJS's essential built-in directives can be easily added to HTML templates to make your theme dynamic.
As described in the official docs, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS's HTML compiler ($compile
) to attach a specified behavior to that DOM element or even transform the DOM element and its children.
These look familiar. It’s a best practice to use these 2 directives when using Angular expressions for creating links. By using these attributes, Angular waits for the interpolation to take place, and then activates the link’s behavior. Otherwise a user might end up on a 404 page or a dynamically-loaded image won’t appear.
Example
<a data-ng-href="{{ product.url }}">
<img data-ng-src="{{ getImagePath(product.imageCollections) }}"
class="img-responsive"
alt="{{ product.name }}">
</a>
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngHref
https://docs.angularjs.org/api/ng/directive/ngSrc
Add this directive to an HTML block to generate repeating elements from an array object like a list of products.
User ng-repeat to easily create a list of:
- Product thumbnails
- Navigation breadcrumbs
- Available product options
- Entire HTML partials like a product tile
Example
<div class="row">
<div class="col-xs-12 col-sm-3"
data-ng-repeat="product in featuredProducts">
<a data-ng-href="{{product.url}}">
<div data-ng-include=" 'views/partials/product-tile.html' "></div>
</a>
</div>
</div>
In this example, a product grid is generated inside the Bootstrap row. These product tile columns are repeated based on the data available. A product tile template is used inside the repeater to provide the HTML structure for each product tile. More on ng-include later.
Note: The variable "product" from product in featuredProducts
is a locally-scoped. You could write foo in featuredProducts
- in which case you would use {{ foo.url }}
in the scope of that block.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngRepeat
These built-in directives do exactly what they say by applying to visibility classes to your elements. These can be used interchangeably.
When ng-hide
evaluates to True or ng-show
evaluates to False - the .ng-hide
class is added to your element with the property display: none !important
Uses for ng-hide and ng-show:
- Show a special banner if an item is on sale
- Show a link to customer reviews if the review count is greater than 1 (or any number)
- Hide a section of the page if no data is present
- Show a specific message to the user based on the number of search results
Remember, these elements are still accessible in the DOM. The remove elements completely use ng-if
Example
<div class="th-product-details__price">
<span>Regular Price: {{ product.pricing.regularPrice | currency }}</span>
<span data-ng-show="product.pricing.salePrice > 0">
<span>Sale Price: {{ product.pricing.salePrice | currency }}</span>
</span>
</div>
In this example we check to see if a Sale Price is present. If the value is greater than zero the sale price exists and is displayed. We don't want to show the label Sale Price:
if there is no data available.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngShow
https://docs.angularjs.org/api/ng/directive/ngHide
Further Reading:
http://scotch.io/tutorials/javascript/how-to-use-ngshow-and-nghide
Similar to ng-hide
and ng-show
, ng-if
differs in that it will remove elements from the DOM when evaluated to false.
Ng-if
can be used for a variety of purposes, including:
- Only adding a customers reviews section to a product page when reviews are enabled
- Adding an element to the DOM when a checkbox is checked
- Displaying a free shipping option when a shopping cart total reaches a set price
Example
<div class="th-product-details__stock-status">
<span data-ng-if="(product.availability.quantityInStock > 0)" class="text-success">
In Stock
</span>
<span data-ng-if="(product.availability.quantityInStock <= 0)" class="text-danger">
Out of Stock
</span>
</div>
In this example we check to see if a product is available by targeting the availability.quantityInStock
data point. If the quantity is greater than 0 the product is considered in stock and the message is displayed. When the quantity is 0 we display the “out of stock” message. This example also utilized Bootstrap’s built-in text styling classes which are incredibly useful and semantic for this type of scenario.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngIf
This directive inserts HTML or plain text in between the tag in which it’s declared. The HTML can be captured from your Javascript files or a JSON object from the API.
Using ng-bind-html
comes in handy when setting up sections of your theme to be easily edited by store owners. Using the admin interface, a store owner can add their own HTML using a WYSIWYG interface which is then inserted into your theme using ng-bind-html
Alternatively, ng-bind
is great for inserting short strings or integers from the product API into your page.
Example
<div class="col-md-12">
<div class="th-product-feature" data-ng-show="product.descriptions.detail">
<h3 class="th-product-feature__title" data-translate="product.description">
Description
</h3>
<p class="th-product-feature__description" itemprop="description"
data-ng-bind-html="product.descriptions.detail"></p>
</div>
<div class="th-product-feature" data-ng-show="product.descriptions.features">
<h3 class="th-product-feature__title" data-translate="product.features">
Features
</h3>
<p class="th-product-feature__description"
data-ng-bind-html="product.descriptions.features"></p>
</div>
</div>
You will notice that there is no text within our <p>
tags, this is because the text is inserted with ng-bind-html
and anything placed between those tags will be replaced. Don't worry too much about data-translate
, just know that it makes translating our sites into different languages incredibly easy and flexible.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngBind
https://docs.angularjs.org/api/ng/directive/ngBindHtml
Similar to ng-bind-html
, ng-include
allows you to load entire HTML templates into sections of your theme. A great example of this is setting an ng-repeat
and then using ng-include
to link to a product-tile HTML partial. When the code runs it will evaluate the ng-repeat
to gather the objects in the array, and then repeat the same HTML layout for each object using the HTML partial.
Example
<div class="row">
<div class="col-xs-12 col-sm-3"
data-ng-repeat="product in featuredProducts">
<a data-ng-href="{{product.url}}">
<div data-ng-include=" 'views/partials/product-tile.html' "></div>
</a>
</div>
</div>
Looking again the example of our product tile repeater, we use the ng-include
directive to pull HTML from a template into our view. This allows use to create multiple product tile templates that can be easily interchanged. Additionally, separating the views make our code more modular.
Example #2 - Index.html
...
<body role=”document” ng-controller=”MainCtrl”>
<div ng-include=" 'views/partials/header.html' "></div>
<!-- Main Content -->
<div role="main" autoscroll="" ng-view="" ></div>
<div ng-include=" 'views/partials/footer.html' "></div>=
</body>
...
Since AngularJS is used to make Single-Page Applications (SPAs), this is a common layout for your index.html
. As you can see the header and footer are loaded with ng-include
. Don’t worry about ng-view
, just know that the Controller declared in the body tag controls the views displayed within the main content area between the header and footer.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngInclude
Use ng-class
to dynamically add CSS classes to elements based on an evaluated expression. A common use case for this in the theme engine would be to add special coloring or a strikethrough to a regular product price when a sale price is present. You could also add disabled styles to buttons if a product is out of stock.
Example
<div class="th-product-tile__price">
<span data-ng-show="product.pricing.regularPrice > 0">
<span data-ng-class="{strike: product.pricing.salePrice > 0}"
data-ng-bind-html="product.pricing.regularPrice | currency">
</span>
</span>
<span class="th-product-tile__price--sale" data-ng-show="product.pricing.salePrice > 0">
<span data-ng-bind-html="product.pricing.salePrice | vnFormattedCurrency"></span>
</span>
</div>
In this example we are adding a special CSS class to our regular price if our product has a sale price. Our class .strike
contains the style text-decoration: line-through
which will strike out the regular price.
Official Docs:
https://docs.angularjs.org/api/ng/directive/ngClass
Further reading:
http://scotch.io/tutorials/javascript/the-many-ways-to-use-ngclass
When writing directives inside our HTML, prefixing our directives with the HTML5 attribute ‘data-’ makes the code W3C compliant and is considered a best practice for production code.
Filters can be added to expressions to fine tune the way data is displayed when an expression evaluates.
For example:
{{ product.price | currency }}
or
<li ng-repeat="product in products | limitTo: 4">
{{ product.name | uppercase }}
</li>
The vertical line ( |
), also called a “pipe” is required when using Angular’s built-in filters. Once you become more familiar with AngularJS you can create your own custom filters.
Here are the most common filters:
number
Formats a number as text.
date
Formats date to a string based on the requested format.
lowercase
Converts string to lowercase.
uppercase
Converts string to uppercase.
currency Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default symbol for current locale is used.
limitTo
Creates a new array or string containing only a specified number of elements. The elements are taken from either the beginning or the end of the source array, string or number, as specified by the value and sign (positive or negative) of limit. If a number is used as input, it is converted to a string.
orderBy
Orders a specified array by the expression predicate. It is ordered alphabetically for strings and numerically for numbers. Note: if you notice numbers are not being sorted correctly, make sure they are actually being saved as numbers and not strings.
Custom Filters (are sweet)
One of our custom filters is called vnFormattedCurrency
. This filter can be added like the regular currency filter onto product prices. It removes the numbers after a decimal if the numbers are zero. However, if a price is $10.99, the 99 is given a special class which decreases the font size and sets its vertical alignment to superscript.
Link: https://docs.angularjs.org/api/ng/filter
Tutorial Video: https://egghead.io/lessons/angularjs-built-in-filters