An Angular JS module for Drupal 7.
npm install angular-drupalAn Angular JS module for Drupal 7 Services.
This Angular module makes it easy to read/write entity data to/from Drupal,
handles user authentication and registration, and makes it easy to retrieve
JSON data from Views.
Here's a very simple Angular app that loads node # 123 from Drupal and then
displays the node's title (via an alert):
``
// My simple app.
angular.module('myApp', ['angular-drupal']).run(['drupal', function(drupal) {
drupal.node_load(123).then(function(node) {
alert(node.title);
});
}]);
// The angular-drupal configuration settings for my simple app.
angular.module('angular-drupal').config(function($provide) {
$provide.value('drupalSettings', {
sitePath: 'http://my-drupal-site.com',
endpoint: 'api'
});
});
`
There are two main parts to the installation and usage of this module. First,
on your Drupal site you need to install the Angular Drupal module, then
install and configure Services module, and then include the angular-drupal
module in your Angular JS application.
https://www.drupal.org/project/angular_drupal
``
drush dl angular_drupal
drush en -y angular_drupal
https://www.drupal.org/project/services
``
drush dl services
drush en -y rest_server
Then create a new endpoint by going to admin/structure/services/add with the
following info:
``
machine name: api
server: REST
path: api
debug: unchecked
session authentication: checked
Then click the edit resources link and check the box next to each resource that
should be available to your app:
``
comment
file
node
system
taxonomy_term
taxonomy_vocabulary
user
Then click Save. After that, click the Server tab and make sure the
following boxes are checked:
``
json
application/json
application/x-www-form-urlencoded
Then click Save. After that flush all of Drupal's caches.
``
drush cc all
As usual, be sure to include the angular-drupal.js file in your app. Thisindex.html
typically is included via the file somewhere after you include theangular.js file:
``
The angular-drupal module comes with a Service called drupal. You can
include this service throughout your app using Angular's dependency injection
mechanism.
The simple app, listed above, injects the drupal service into the app's runnode # 123
function. Then when the app runs it loads from Drupal and then
alerts the node's title.
Notice how we used a config function on the angular-drupal module in the
simple app to provide the URL to our Drupal site, as well as the machine name of
the Services endpoint. Without this, the module won't know how to connect to
our Drupal site, so this must be added to our app as in the example above.
drupal.connect().then(function(data) {
if (data.user.uid) { alert('Hello ' + data.user.name + '!'); }
else { alert('Please login.'); }
});
`$3
`
var account = {
name: 'bob',
mail: 'bob@example.com',
pass: 'secret'
};
drupal.user_register(account).then(function(data) {
alert('Registered user # ' + data.uid);
});
`$3
`
drupal.user_login('bob', 'secret').then(function(data) {
if (data.user.uid) {
alert('Hello ' + data.user.name + '!');
}
});
`$3
`
drupal.user_logout().then(function(data) {
if (!data.user.uid) {
alert('Logged out!');
}
});
`NODES
$3
`
var node = {
type: 'article',
title: 'Hello world',
language: 'und',
body: { und: [ { value: 'How are you?' }] }
};
drupal.node_save(node).then(function(data) {
alert('Created node: ' + data.nid);
});
`$3
`
drupal.node_load(123).then(function(node) {
alert('Loaded node: ' + node.title);
});
`$3
`
var node = {
nid: 123,
title: 'Goodbye world',
language: 'und',
body: {
und: [ { value: 'I am fine, thank you.' }]
}
};
drupal.node_save(node).then(function(data) {
alert('Updated node: ' + data.nid);
});
`$3
`
drupal.node_delete(123).then(function(data) {
if (data[0]) {
alert('Deleted node.');
}
});
`$3
`
var query = {
parameters: {
'type': 'article'
}
};
drupal.node_index(query).then(function(nodes) {
var msg = '';
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
msg += 'Loaded node: ' + node.title + '\n';
}
alert(msg);
});
`USERS
$3
To create a new user account, the user must have the Administer users
permission enabled in Drupal.
`
var account = {
name: 'jane',
mail: 'jane@example.com',
pass: 'secret-sauce'
};
drupal.user_save(account).then(function(data) {
alert('Created new user #' + data.uid);
});
`$3
`
drupal.user_load(1).then(function(account) {
alert('Loaded user: ' + account.name);
});
`$3
To update an existing user account, the user must have the Change own username
or Administer users permission enabled in Drupal.
`
var account = {
uid: 123,
name: 'john'
};
drupal.user_save(account).then(function(data) {
alert('Name changed to: ' + data.name);
});
`$3
The user must have the Administer users permission to delete a user account.
`
drupal.user_delete(123).then(function(data) {
if (data[0]) {
alert('Deleted user.');
}
});
`$3
`
var query = {
parameters: {
'name': 'bob'
}
};
drupal.user_index(query).then(function(users) {
var msg = '';
for (var i = 0; i < users.length; i++) {
var user = users[i];
msg += 'Loaded user: ' + user.name + '\n';
}
alert(msg);
});
`COMMENTS
$3
`
var comment = {
nid: 123,
subject: 'Hello world',
comment_body: { und: [ { value: 'How are you?' } ] }
};
drupal.comment_save(comment).then(function(data) {
alert('Created comment: ' + data.cid);
});
`$3
`
drupal.comment_load(123).then(function(comment) {
alert('Loaded comment: ' + comment.subject);
});
`$3
`
var comment = {
cid: 456,
subject: 'Goodbye world',
comment_body: { und: [ { value: 'I am fine, thank you.' }] }
};
drupal.comment_save(comment).then(function(data) {
alert('Updated comment: ' + data.cid);
});
`$3
`
drupal.comment_delete(123).then(function(data) {
if (data[0]) {
alert('Deleted comment.');
}
});
`$3
`
var query = {
parameters: {
'nid': 123
}
};
drupal.comment_index(query).then(function(comments) {
var msg = '';
for (var i = 0; i < comments.length; i++) {
var comment = comments[i];
msg += 'Loaded comment: ' + comment.subject + '\n';
}
alert(msg);
});
`FILES
$3
`
var base_64_encoded_image = 'abc...xyz';
var file = {
file: base_64_encoded_image,
filename: 'my_image.jpg',
filepath: 'public://my_image.jpg'
};
drupal.file_save(file).then(function(data) {
alert('Saved file # ' + data.fid);
});
`$3
To load a file the user must have the Get any binary files permission in
Drupal.
`
drupal.file_load(123).then(function(file) {
alert('Loaded file: ' + file.filename);
});
`TAXONOMY TERMS
$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_NEW/7
var taxonomy_term = {
vid: 1,
name: 'Hello world'
};
drupal.taxonomy_term_save(taxonomy_term).then(function(data) {
if (data[0] == 1) { // SAVED_NEW
alert('Created taxonomy term.');
}
});
`$3
`
drupal.taxonomy_term_load(123).then(function(term) {
alert('Loaded term: ' + term.name);
});
`$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_UPDATED/7
var taxonomy_term = {
vid: 1,
tid: 123,
name: 'Goodbye world'
};
drupal.taxonomy_term_save(taxonomy_term).then(function(data) {
if (data[0] == 2) { // SAVED_UPDATED
alert('Updated taxonomy term.');
}
});
`$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_DELETED/7
drupal.taxonomy_term_delete(123).then(function(data) {
if (data[0] == 3) { // SAVED_DELETED
alert('Deleted taxonomy term.');
}
});
`$3
`
var query = {
parameters: {
'vid': 1
}
};
drupal.taxonomy_term_index(query).then(function(taxonomy_terms) {
var msg = '';
for (var i = 0; i < taxonomy_terms.length; i++) {
var taxonomy_term = taxonomy_terms[i];
msg += 'Loaded taxonomy term: ' + taxonomy_term.name + '\n';
}
alert(msg);
});
`TAXONOMY VOCABULARIES
$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_NEW/7
var taxonomy_vocabulary = {
name: 'Fruits',
machine_name: 'fruits',
description: 'Fruit is delicious.'
};
drupal.taxonomy_vocabulary_save(taxonomy_vocabulary).then(function(data) {
if (data[0] == 1) { // SAVED_NEW
alert('Created taxonomy vocabulary.');
}
});
`$3
`
drupal.taxonomy_vocabulary_load(1).then(function(vocabulary) {
alert('Loaded vocabulary: ' + vocabulary.name);
});
`$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_UPDATED/7
var taxonomy_vocabulary = {
vid: 2,
name: 'Colorful Fruits',
machine_name: 'fruits',
description: 'Colorful fruit is even more delicious.'
};
drupal.taxonomy_vocabulary_save(taxonomy_vocabulary).then(function(data) {
if (data[0] == 2) { // SAVED_UPDATED
alert('Updated taxonomy vocabulary.');
}
});
`$3
`
// @see https://api.drupal.org/api/drupal/includes!common.inc/constant/SAVED_DELETED/7
drupal.taxonomy_vocabulary_delete(123).then(function(data) {
if (data[0] == 3) { // SAVED_DELETED
alert('Deleted taxonomy vocabulary.');
}
});
`$3
`
var query = {
parameters: {
'name': 'tags'
}
};
drupal.taxonomy_vocabulary_index(query).then(function(taxonomy_vocabularys) {
var msg = '';
for (var i = 0; i < taxonomy_vocabularys.length; i++) {
var taxonomy_vocabulary = taxonomy_vocabularys[i];
msg += 'Loaded taxonomy vocabulary: ' + taxonomy_vocabulary.name + '\n';
}
alert(msg);
});
`Views
If you install the Views JSON module, which is available as a sub module of the
Views Datasource module (https://www.drupal.org/project/views_datasource), you
can easily set up a View page display to return JSON to your app:
`
var path = 'articles'; // The Drupal path to the Views JSON page display.
drupal.views_json(path).then(function(rows) {
angular.forEach(rows, function(row, i) {
console.log(row.title);
});
});
`For more information on creating Views JSON page displays, read this:
http://drupalgap.org/node/220
X-CSRF-Token
The angular-drupal module automatically takes care of the X-CSRF-Token when
it is needed. If you need to manually get the token it can easily be retrieved:
`
drupal.token().then(function(token) {
console.log('Got the token: ' + token);
});
`DISCLAIMER
I, Tyler Frankenstein`, admit I am very much a n00b when it comes to Angular