How to integrate an Angular Widget into Yii
This is a brief guide on how to integrate Angular into an existing Yii 2.0 web app. The instructions will provide you with the basics on how to create a very simple Angular widget which will show the logged in user’s details, add the widget to a Yii view and pass some basic information into the widget. This guide will also briefly touch on how to load more information via RESTful web calls.
Things you’ll need
- Existing Yii 2.0 Advanced Template Web App
- Basic knowledge of Angular, Yii 2.0, Grunt and Bower
1. Getting Ready
In this how to guide we are going to make a very simple widget which will be passed an id, and will show a user’s details based on the id supplied. There will only be two modules used, the frontend which is where the angular widget will be shown, and an api module which will be used to load the user’s information. We use MAMP Pro to setup the modules to subdomains, the domain we are going use throughout is example.dev for the “frontend” module and api.example.dev for the api module.
Here is the link for the site before adding code for this guide: https://bitbucket.org/toruinteractive/blog_yii_angular/get/step_1.zip
2. Creating a basic Angular Widget
First you need to determine which modules you will require your new Angular widget to be accessible from. In theory it doesn’t really matter which module, but at Toru Interactive we tend to organise widgets into modules depending on how they are accessed, i.e. if a widget will only be available to the “frontend” module we will add a “widgets” folder to the front end and likewise with the backend. If the widget will need to be accessed from multiple modules we will add a widgets folder to the common module and store the widget there instead as it is a ‘common’ widget to multiple modules. You do not need to follow this convention, but we have found on larger projects that this is a very useful way to organise widgets.
For the purposes of this guide we are going to access the widget from the front end, so go ahead and add a “widgets” folder under the “frontend” module folder, in the widgets folder create a “details” folder.
Because we use Grunt to minify our angular widgets we add another folder called “src” to the details folder, generally we call the folder with the source files “src” and send the minified files to a build folder, these both sit next to each other in the details folder. So go ahead and add the “src” folder, the build will be added automatically by Grunt.
Next we need to create the angular app that we are going to show on the site, to start with we are going to make a very simple three file app. I’m going to assume you know about factories, directives, controllers and templates, if not, checkout this really great tutorial from Angular which works through these key components of an Angular app. The first thing we are going to create is the factory, the factory is going to be very basic to start, and its just a holder at the moment ready for getting the user’s details.
Then we are going to add the details directive, which again is going to be very basic, its only going to allow us to pull in the factory and show the template.
So we can check that everything is working the template file is going to show, so enter as text into the details.tpl.html file
to start listening for changes to the angular widget, if you save one of the files you should see a new ‘build’ folder appear in the root.
Here is the link to the code from this step: https://bitbucket.org/toruinteractive/blog_yii_angular/get/step_1.zip
3. Adding the widget to Yii
Now that you have an angular widget you probably want to see it in action right? We need to setup Yii to import the necessary libraries, we use Bower and Composer to manage our library imports, to allow Composer to pull in Bower libraries you just need to add line 6 to the list of required packages in Composer, see below.
Next we need to tell Bower what libraries we want to import, we can do this in Composer in the “extra” section, add a new key “require-bower” and make it an object, then add the angular libraries as you would in bower, see below.
Now if you update composer you should see a bower.json file has been generated and the two angular libraries are now in the vendor/bower folder. n.b. don’t manually edit the bower.json file as next time you run composer it will be overwritten.
Now we need to make a Yii widget to load our Angular App, in the details folder we need to make two new files, the first one will be “Details.php”.
The above code registers the asset that will pull in the angular libraries and the angular app minified file. It then adds the HTML that will trigger the angular app and finally it bootstraps the app. You can add the bootstrap code directly to the layout file, but we find that bootstrapping the widget allows widgets to be added on an ‘as and when’ basis rather then including all apps all of the time, this helps with load speed and we feel its just a more efficient way of loading widgets.
So we still need to load in the angular libraries, lets go ahead and make a “DetailsAsset.php” file in the details folder. In this file we are going to make two asset bundles, the first one DetailsAsset will load the minified angular app and also set the other required assets, one of which being the second asset bundle we are going to create. The second asset bundle imports the two angular libraries we downloaded from Bower, see below.
n.b. while you are developing the widget you should set forceCopy on Line 7 to true, this forces the changes you make to be shown to the user. When you go live you should change it back to false, it makes page loading much quicker when forceCopy is set to false.
So now we have made our Yii widget we can add it to a view, go to the site/index.php file and clear out the jumbotron and body-content divs. Then we need to declare the Details class name and then echo the widget, see Lines 2 and 7–9 below.
If you now navigate to http://example.dev/ you should see as the image below.
Here is the link to the code from this step: https://bitbucket.org/toruinteractive/blog_yii_angular/get/step_3.zip
4. RESTful API calls
So we have an Angular/Yii widget, but it doesn’t do anything, what would be really useful is if it could pull information from the website right? So we said earlier that we would load a user’s details, we could convert the user model to JSON and pass into Angular as a scope variable, but this seems a bit cumbersome and it wouldn’t take much information before this starts to get very messy. Yii provides us a way to do this using RESTful API calls, there is however a snag with this, to be properly RESTful it should also be stateless (i.e. it shouldn’t know who is logged in!), but thats fine we can pass the API call the user’s id from the UserIdentity that Yii provides.
First we should setup our data, in the api module in Yii add a new Controller called UserController.php and it inherits from the yii\rest\ActiveController class. This controller is going to return data from the User model, which is automatically made with any new Yii project, so we’re going to set the modelClass to common\models\User and the controller will automatically return data for this model. Next we need to setup the routing in the “api\config\main.php” file, we need to add ‘user’ to the urlManager, rules controller array, see line 11 below.
If you haven’t already, if you create a database, link it to the Yii app, add a user table and add some rows with data, if you want to follow this guide exactly we created the user table with the following command:
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`full_name` varchar(128) DEFAULT NULL,
`address` varchar(64) DEFAULT NULL,
`county` varchar(64) DEFAULT NULL,
`post_code` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
As Yii provides us with some default actions when using the RESTful ActiveController, if we go to http://api.example.dev/users we can see all of the users and all of their data, see below.
If we then pick one of the users and add their id to the url you can see only their information, so we have a user with the id of 1, if we go to http://api.example.dev/users/1 we can see all of their information.
So, we can now view the data from the api subdomain, but if we were to try and load this from http://example.dev/ we would get a cross domain error, this is a security feature built into all of the popular browsers. To get around this you can make the requesting domain as safe, you can do this with the following code in the UserController in the API module.
Now we can access our data, we need go back to the angular widget, if we wanted to get user 1 we would need to pass data to the angular app. This is done in the Details.php file as you would if the angular app was being called from a static page, see below where the attribute “user-id” is being set to 1, if your app allows you to login you can set “user-id” to Yii::$app->user->id to dynamically get the data for the currently logged in user.
Next we need to call the api to get the user’s details, if you have followed the Angular tutorial you can probably work this bit out for yourself. At Toru Interactive we setup our factory a little differently as we like to perform any data manipulation in the factory as well as using it to make the API calls. So as you can see below, we have an “api” key on the factory object which returns the resource, here we can setup the call to http://api.example.dev/users/1, as we are using the userId passed to the Angular app we can swap “users/1” to “users/:id”, this allows us to pass a variable into the query.
Next we can setup the call from the “details.directive.js” file and pass in the “userId” scope variable, then set the user variable on the scope to equal the response from the call, see below.
Then we just need to display the data to the user, so all we need to do is update the template and we’re done.
If you go to http://example.dev/ now you should something similar to the image below.
Here is the link to the code from this step: https://bitbucket.org/toruinteractive/blog_yii_angular/get/step_4.zip
5. What Next?
This guide has shown you how to make an angular app, turn it into a Yii widget and retrieve data from the database via a RESTful web call. Using the steps above you can go on to make much more powerful angular widgets which can allow you to login to the site, search your data and show the results without the delay waiting for pages to load. The combination between Angular and RESTful when submitting form data is awesome, Because of the way angular binds data its really simple and efficient to update views, you can easily show users that something is happening, that it has finished or that there was an error.
If there is any topic that you would like me to cover please email or tweet me.
- Angular API. https://docs.angularjs.org/api
- Angular Tutorial. https://docs.angularjs.org/tutorial
- Yii API. http://www.yiiframework.com/doc-2.0/index.html
- Yii RESTful Web Services. http://www.yiiframework.com/doc-2.0/guide-rest-quick-start.html
- Bower. http://bower.io/
- Example Repository. https://bitbucket.org/toruinteractive/blog_yii_angular
Read more about Widgets on our website…