32

Table of Contents - Add docshare01.docshare.tips to …docshare01.docshare.tips/files/29796/297963315.pdfTable of Contents How To Create Single Page Application in minutes! 2 This

Embed Size (px)

Citation preview

1. GettingStarted2. Overview3. Introduction4. Preparation5. CreateWebService6. CreateWebClient7. Customization8. Conclusion

TableofContents

HowToCreateSinglePageApplicationinminutes!

2

ThisisademoandatutorialshowinghowtodevelopanapplicationusingYii2.0forcreatingRESTAPIandthenusingitfromUIbuiltwithAngularJS.

Tutorialisavailablehere.Bookisavailablehere

Inordertoinstalldemoclonethisrepository:

gitclonehttps://github.com/hscstudio/angular1-yii2angular1-yii2

cdangular1-yii2

Thenimportdatabaseangular_spa.sql.

Afterit'sdonerunthefollowing:

cdweb-service

composerupdate--prefer-dist

Setdatabaseconfiginweb-service\config\db.php.

Setuptwohostsinyourwebserver.Oneshouldpointtoweb-client,aothertoweb-service/web.

ThensetserviceBasevariableinweb-client\app.jstopointtoweb-serviceURL.

Freeopensource

HowToCreateSinglePageApplicationinminutes!withAngularJs1.3andYii2.0

Introduction

Installingdemo

License

HowToCreateSinglePageApplicationinminutes!

3GettingStarted

0.1(Alpha-11/05/2015)0.2(Beta-12/05/2015)

Changelog

HowToCreateSinglePageApplicationinminutes!

4GettingStarted

IntroductionPreparationCreatingWebServiceCreatingWebClientCustomizationConclusion

ThisguideisanOpenSourceprojectsoyourcontributionisverywelcome.

Inordertogetstarted:

Clonethisrepository.CheckREADME.md.Readeverythingindocumentation.

Sendpullrequests.

Asidefromcontributingviapullrequestsyoumaysubmitissues.

OfficialYii2.0guide.Yii2.0sourcecode.ExampleofAngularJS+Yii2.0bygithubjeka.

HafidMukhlasin-ProjectLeader/IndonesianYiideveloper.AlexanderMakarov-Editorial/Yiicoreteam.

HowToCreateSinglePageApplicationinminutes!withAngularJs1.3andYii2.0

TableOfContents

Development

Reference

OurTeam

HowToCreateSinglePageApplicationinminutes!

5Overview

We'dliketothankourcontributorsforimprovingtheguide.Thankyou!

HowToCreateSinglePageApplicationinminutes!

6Overview

Fromthisguideyou'lllearnhowtocreatesinglepageapplication(SPA)inminutesusingAngularJsandYiiFramework2.0.TheapplicationwillimplementaCreateReadUpdateDelete(CRUD)dataprocessing.UserinterfaceofthisapplicationwillbeimplementedusingAngularJs.DatawillbeprovidedbyAPIcreatedusingYiiFramework2.0.

Therewillbetwoapplications:

WebClientApplication.TheoneprovidingUI.WebServiceApplication.Theonedealingwithdata.

Note:ForeasiermaintenanceitisrecommendedthatyoudevelopyourRESTfulAPIsasaseparateapplicationwhichisseparatedfrombothwebsiteandadminpartsoftheapplication.

Sinceclientandserviceareseparated,technologystackusedineachcasevaries.

ForclientapplicationweuseHTML,JS,andCSS.Atleastsomeknowledgeofallthreeismandatorytofollowthistutorial.

AngularJs1.3

AngularJsisapopularJavaScriptframework.Itdoesnotmatterifyoudonotknowtoomuchaboutityet.Itisrelativelyeasytoundestandifyou'refamiliarwithJavaScriptandYii.Ifyou'veusedjQuerybefore,forgetaboutitforawhilesinceconceptsofAngularJsaredifferent.

CSSBootstrap3

InitiallydevelopedbyTwitterteam,CSSBootstrapiswidelyusedfrontendUIframework.ItisacollectionofreadytouseJavaScriptandCSSthatallowsustodesignabeautifuluserinterfacequickly.

Introduction

Structure

TechnologyBehindtheScenes

WebClientApplication

HowToCreateSinglePageApplicationinminutes!

7Introduction

Forservicepartwe'llusePHPandMySQL.AsaPHPframeworkwe'lluseYiiFramework2.0

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

WebServiceApplication

HowToCreateSinglePageApplicationinminutes!

8Introduction

It'stimetostartpreparingapplications.Thefollowingareseparatestepsforclientandserviceapplications.

Createawebrootdirectory(usuallyit'sweb,htdocs,public_html,wwworalikename).Insideadd

directoriesnamedassets,controllers,modelsandviews.

Thestructurewe'vejustcreatedissimilartothestructureusedbyYii.Youcanadjustitasyoulikebutforthistutorialwe'llsticktoYiiconventioninordertomakeiteasiertounderstand.

Let'sexplainallthesedirectoriesabit:

assetscontainsAngularJsandCSSBootstraplibraries.

controllersisforAngularJscontrollers.

modelsisforserviceswhichdealwithRESTfulCRUDAPIwe'regoingtobuild.

viewsisforpartialpages.MuchlikeviewsinYii.

Downloadalibraryfromhttp://getbootstrap.com/andextractittoassetsdirectorylikethefollowing:

assets

bootstrap

js

css

font

Downloadalibraryfromhttp://angularjs.org/,andextractitintoassetsdirectorylikethefollowing:

assets

bootstrap

angular

angular.js

angular.min.js

...

InordertouseAngularJsandCSSBootstrapweneedtocreateanHTMLfilehtmlfilewhichwillusebothlibraries.Createindex.htmlandputitintoyourwebrootdirectory:

Preparations

WebClientApplication

GetCSSBootstrap

GetAngularJs

IncludeAngularJsandCSSBootstrapintoHTML

HowToCreateSinglePageApplicationinminutes!

9Preparation

<!DOCTYPEhtml>

<html>

<head>

<!--CSS-->

<linkrel="stylesheet"href="assets/twitter-bootstrap/css/bootstrap.min.css"/>

<linkrel="stylesheet"href="assets/twitter-bootstrap/css/bootstrap-theme.min.css"/>

</head>

<body>

<!--JS-->

<scriptsrc="assets/angular/angular.min.js"></script>

<scriptsrc="assets/angular/angular-route.min.js"></script>

</body>

</html>

InstallYii2.0BasicprojecttemplateasdescribedinYiiguide.ItispreferredtouseComposerlikethefollowing:

composerglobalrequire"fxp/composer-asset-plugin:1.0.0"

composercreate-project--prefer-distyiisoft/yii2-app-basicweb-service

Alternativelyyoucandoitmanuallydownloadingandextractingarchiveasdescribedatthesameguidepage.

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

WebServiceApplication

HowToCreateSinglePageApplicationinminutes!

10Preparation

Nowthatprepartionsdonewe'llstartwithservicepartofourapplicationusinghighperformanceYii2.0PHPframework.It'sagreatfitsinceithasbuiltinfunctionalitythatallowskickstartingwithRESTfulAPIseasily.Basicsarealreadydoneforyouensuringmanydetailstobesetupcorrectlywhilemoreadvancedthingscouldbeimplementedasneeded.

We'llusedatabasenamedangular_spasocreateit.Thenaddbooktablewithfollowingstructure:

Youcanuseangular_spa.sqlinordertoimportit.

Insertsomedatainthetable,youcancreatemoretablesbutforthesakeofsimplicity,inthistutorialwe'lluseonlybook.

Openconfig/db.phpintherootofYiiwebserviceapplication.Modifydbconfigurationtospecifyyour

MySQLsettings:

return[

'class'=>'yii\db\Connection',

'dsn'=>'mysql:host=localhost;dbname=angular_spa',

'username'=>'root',//specifyyourusernamehere

'password'=>'',//specifyyourpasswordhere

'charset'=>'utf8',

];

UseGiitogeneratemodelclassfordatabasetables(wehaveonlyonesofar).RefertoYii'sguidefordetailsonhowtodoit.

CreatingWebService

CreateDatabaseStructure

ConfigureDatabaseConnection

CreateModels

HowToCreateSinglePageApplicationinminutes!

11CreateWebService

Youshouldgetmodels/Book.phpwiththefollowingcontent:

namespaceapp\models;

useYii;

classBookextends\yii\db\ActiveRecord

{

publicstaticfunctiontableName()

{

return'book';

}

publicfunctionrules()

{

return[

[['title','author','publisher','year'],'required'],

[['id','year'],'integer'],

[['title'],'string','max'=>255],

[['description'],'string'],

[['author','publisher'],'string','max'=>50]

];

}

}

IfyouarenotfamiliarwithRESTsupportinYii2.0,youcangetandideaaboutitbyreadingcorrespondingguidesection.

There'snoabilitytogenerateRESTCRUDinYii'sGiicodegeneratorbutdoingitwithoutitiseasyandfun.

First,createBookController.phpinthecontrollersdirectory.

namespaceapp\controllers;

useyii\rest\ActiveController;

classBookControllerextendsActiveController

{

//adjustthemodelclasstomatchyourmodel

public$modelClass='app\models\Book';

publicfunctionbehaviors()

{

return

\yii\helpers\ArrayHelper::merge(parent::behaviors(),[

'corsFilter'=>[

'class'=>\yii\filters\Cors::className(),

],

]);

SetupYiiRESTfulApplication

CreateRESTController

HowToCreateSinglePageApplicationinminutes!

12CreateWebService

}

}

Thecontrollerclassextendsfromyii\rest\ActiveController.ByspecifyingmodelClassas

app\models\Book,thecontrollerknowswhichmodelcanbeusedforfetchingandmanipulatingdata.

We'readdingCORSbehaviorinordertograntaccesstothirdpartycode(AJAXcallsfromexternaldomain).

Ifyouhavemoremodels,createalikecontrollersforeachone.

Modifyapplicationconfiguration,urlManagercomponentinweb.phpintheconfigdirectory:

'urlManager'=>[

'enablePrettyUrl'=>true,

'enableStrictParsing'=>true,

'showScriptName'=>false,

'rules'=>[

['class'=>'yii\rest\UrlRule','controller'=>'book'],

],

]

TheaboveconfigurationmainlyaddsaURLruleforthebookcontrollersothatthebookdatacanbeaccessedandmanipulatedwithprettyURLsandmeaningfulHTTPverbs.Ifyouhavemorecontrollers,specifythemasarray:

'rules'=>[

['class'=>'yii\rest\UrlRule','controller'=>['book','user','employee','etc']],

],

Note:IfyouareusingApacheasawebserver,youneedtoadda.htaccessfiletoyourwebroot.Incaseofnginxyoudon'tneedtodoit.

TolettheAPIacceptinputdatainJSONformat,configuretheparserspropertyoftherequest

applicationcomponenttousetheyii\web\JsonParser:

'request'=>[

'parsers'=>[

'application/json'=>'yii\web\JsonParser',

]

]

ConfiguringURLRules

EnableJSONInput

HowToCreateSinglePageApplicationinminutes!

13CreateWebService

Info:Theaboveconfigurationisoptional.Withoutit,theAPIwouldonlyrecognizeapplication/x-

www-form-urlencodedandmultipart/form-datainputformats.

Notit'stimetocheckwhatwe'vecreatedsofarwiththatlittleeffort.WealreadyhaveRESTfulAPIforgettingandmanagingbookdata:

GET/books:listallbookspagebypage;

HEAD/books:showtheoverviewinformationofbooklisting;

POST/books:createanewbook;

GET/books/123:returnthedetailsofthebook123;

HEAD/books/123:showtheoverviewinformationofbook123;

PATCH/books/123andPUT/books/123:updatethebook123;

DELETE/books/123:deletethebook123;

OPTIONS/books:showthesupportedverbsregardingendpoint/books;

OPTIONS/books/123:showthesupportedverbsregardingendpoint/books/123.

Info:Yiiwillautomaticallypluralizecontrollernamesforuseinendpoints.Youcanconfigurethisusingtheyii\rest\UrlRule::$pluralize.

YoumayalsoaccessyourAPIviaWebbrowserbyenteringhttp://localhost/web-service/web/books.However,youmayneedsomebrowserpluginstosendspecificrequestheaders.Forexample,PostmanChromeExtension:

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

Summary

HowToCreateSinglePageApplicationinminutes!

14CreateWebService

Itistimetocreateawebclientor,inotherwords,theuserinterfacefortheapplicationservicewe'vecreatedpreviously.WewilluseAngularJsasJavaScriptframeworkandCSSbootstraptostyleourUI.

Entryscriptisascriptthathandlesallapplicationrequests.Inourcaseitwillbeindex.htmlfilecontainedinthewebdirectory.

Addng-appattributetohtmltag.Asanexample,we'llusespaAppasthevalue.

<!DOCTYPEhtml>

<!--defineangularapp-->

<htmlng-app="spaApp">

<head>

<!--CSS-->

Addng-controllerattributetobodytag.Controllernameisindex.

</head>

<!--defineangularcontroller-->

<bodyng-controller="index">

Addthefollowingcontentinsidebodytag:

<bodyng-controller="index">

<navclass="navbarnavbar-default">

<divclass="container">

<divclass="navbar-header">

<aclass="navbar-brand"href="#/">SinglePageApplication</a>

</div>

<ulclass="navnavbar-navnavbar-right">

<li><ahref="#/"><iclass="glyphiconglyphicon-home"></i>Home</a></li>

<li><ahref="#/site/about"><iclass="glyphiconglyphicon-tag"></i>About</a></li>

<li><ahref="#/site/contact"><iclass="glyphiconglyphicon-envelope"></i>Contact

</ul>

</div>

</nav>

<divid="main"class="container">

CreatingWebClient

SetupApplicationEntryScript

DefineAngularApp

DefineDefaultAngularController

CreateMainMenu

HowToCreateSinglePageApplicationinminutes!

15CreateWebClient

<!--angulartemplating-->

<!--thisiswherecontentwillbeinjected-->

<divng-view></div>

</div>

<footerclass="text-center">

<p>Yii2.0.3+AngularJs1.3.15</p>

</footer>

Navbarisusedformenu,mainispagecontainer.Footeris,obviously,afooter.

Importantthinghereisanidofindivwithcontainerclass:

<divid="main"class="container">

<!--angulartemplating-->

<!--thisiswherecontentwillbeinjected-->

<divng-view></div>

</div>

Dynamiccontentfromotherfilesorpageviewswillbeplacedinto<divng-view></div>.

Themainmoduleisintendedtocontrolotherscriptssuchassubmodule.Wenameitapp.jsandplaceitintothewebrootofthewebclient:

'usestrict';

//adjusttotheyoururlofwebservice

varserviceBase='http://127.0.0.1/web-service/web/'

//declareapplevelmodulewhichdependsonviews,andcomponents

varspaApp=angular.module('spaApp',[

'ngRoute',

'spaApp.site',

]);

//submoduledeclaration

varspaApp_site=angular.module('spaApp.site',['ngRoute'])

spaApp.config(['$routeProvider',function($routeProvider){

//configdefaultroute

$routeProvider.otherwise({redirectTo:'/site/index'});

}]);

Defaultrouteis/site/index.ThisroutewillhandledbyspaApp.sitesubmodule.

AftercreatingspaApp.sitesubmoduleweneedtodefinewhatthatsubmoduledoes.Createafile

site.jsincontrollersdirectory.

CreateMainModuleandSubModule

CreateSubModuleDefinition

HowToCreateSinglePageApplicationinminutes!

16CreateWebClient

'usestrict';

spaApp_site.config(['$routeProvider',function($routeProvider){

$routeProvider

.when('/site/index',{

templateUrl:'views/site/index.html',

controller:'index'

})

.when('/site/about',{

templateUrl:'views/site/about.html',

controller:'about'

})

.when('/site/contact',{

templateUrl:'views/site/contact.html',

controller:'contact'

})

.otherwise({

redirectTo:'/site/index'

});

}])

.controller('index',['$scope','$http',function($scope,$http){

//createamessagetodisplayinourview

$scope.message='EveryonecomeandseehowgoodIlook!';

}])

.controller('about',['$scope','$http',function($scope,$http){

//createamessagetodisplayinourview

$scope.message='Look!Iamanaboutpage.';

}])

.controller('contact',['$scope','$http',function($scope,$http){

//createamessagetodisplayinourview

$scope.message='Contactus!JK.Thisisjustademo.';

}]);

Thisfileissubmoduletohandlesiteviews.ItisverysimilartoYii'sSiteController:

spaApp_site.config(['$routeProvider',function($routeProvider){

$routeProvider

.when('/site/index',{

templateUrl:'views/site/index.html',

controller:'index'

})

...

...

.otherwise({

redirectTo:'/site/index'

});

}])

Thisisroutingconfigurationofthissubmoduleonly.EveryroutehasmaytemplateUrland

controller.

templateUrlisanexternalHTMLfilethatisusedaspartialcontent.QuitesimilartoYiiviews.

controllerisanameofcontrollerthatpreparestemplatedatasuchasvariables.Itissimlarto

whatYiicontrollerdoes.

HowToCreateSinglePageApplicationinminutes!

17CreateWebClient

.otherwisetellstheapplicationwhattodoifnoroutematches.

.controller('index',['$scope','$http',function($scope,$http){

//createamessagetodisplayinourview

$scope.message='EveryonecomeandseehowgoodIlook!';

}])

$scopeisascopethatcanbehandledbytheangularappinthiscaseisallthetagsunderthetagwhich

ismarkedwithng-app

$scope.message,messageisvariabelinfiletemplateUrl,letsayviews/site/index.html,pointto

Aftercreatingmainmoduleapp.jsandsubmodulesite.js,wemustincludeitinanentryscriptof

appindex.html:

<scriptsrc="assets/angular/angular-animate.min.js"></script>

<!--Includethisjs-->

<scriptsrc="app.js"></script>

<scriptsrc="controllers/site.js"></script>

</body>

Createatemplatefiletobeusedbycontrollerinviewsdirectory.Thefilenamewouldbesite/index.html:

<divclass="jumbotrontext-center">

<h1>HomePage</h1>

<p>{{message}}</p>

</div>

Createsite/contact.html:

<divclass="jumbotrontext-center">

<h1>ContactPage</h1>

<p>{{message}}</p>

</div>

Createsite/about.html:

<divclass="jumbotrontext-center">

<h1>AboutPage</h1>

<p>{{message}}</p>

IncludeMainModuleandSubModule

CreateTemplateFile

HowToCreateSinglePageApplicationinminutes!

18CreateWebClient

</div>

Theseviewsaresimpleplaceholdersfornow.

http://localhost/web-client

AddglobalJavaScriptvarableserviceBasethatreferstoyourYii2.0webservice.Thenaddasub

modulecalledspaApp.book:

'usestrict';

varserviceBase='http://127.0.0.1/web-service/web/'

//Declareapplevelmodulewhichdependsonviews,andcomponents

varspaApp=angular.module('spaApp',[

'ngRoute',

'spaApp.site',

'spaApp.book',

]);

varspaApp_site=angular.module('spaApp.site',['ngRoute'])

varspaApp_book=angular.module('spaApp.book',['ngRoute']);

spaApp.config(['$routeProvider',function($routeProvider){

$routeProvider.otherwise({redirectTo:'/site/index'});

}]);

book.jswillhandleCRUDdataprovidedbyRESTserviceisisprettymuchwhatmodelsaredoingin

Yii.

'usestrict';

spaApp_book.factory("services",['$http','$location','$route',

function($http,$location,$route){

varobj={};

obj.getBooks=function(){

return$http.get(serviceBase+'books');

Testyourapplication

Modifyapp.js

Createbook.jsinmodelsdirectory

HowToCreateSinglePageApplicationinminutes!

19CreateWebClient

}

obj.createBook=function(book){

return$http.post(serviceBase+'books',book)

.then(successHandler)

.catch(errorHandler);

functionsuccessHandler(result){

$location.path('/book/index');

}

functionerrorHandler(result){

alert("Errordata")

$location.path('/book/create')

}

};

obj.getBook=function(bookID){

return$http.get(serviceBase+'books/'+bookID);

}

obj.updateBook=function(book){

return$http.put(serviceBase+'books/'+book.id,book)

.then(successHandler)

.catch(errorHandler);

functionsuccessHandler(result){

$location.path('/book/index');

}

functionerrorHandler(result){

alert("Errordata")

$location.path('/book/update/'+book.id)

}

};

obj.deleteBook=function(bookID){

return$http.delete(serviceBase+'books/'+bookID)

.then(successHandler)

.catch(errorHandler);

functionsuccessHandler(result){

$route.reload();

}

functionerrorHandler(result){

alert("Errordata")

$route.reload();

}

};

returnobj;

}]);

Therearemultiplefunctionssuchasobj.getBooks,obj.createBook,etc.whicharepassingdatato

RESTfulendpoints.Forexample,thefollowingwillgetalistofthebooksusingGET.Seethisguide.

obj.getBooks=function(){

return$http.get(serviceBase+'books');

}

CreateabookusingPOST:

obj.createBook=function(book){

return$http.post(serviceBase+'books',book)

HowToCreateSinglePageApplicationinminutes!

20CreateWebClient

UpdateabookusingPUT:

obj.updateBook=function(book){

return$http.put(serviceBase+'books/'+book.id,book)

Createbook.jsincontrollersdirectory.ItwillhandlebookviewslikeYiicontrollerdoes:

'usestrict';

spaApp_book.config(['$routeProvider',function($routeProvider){

$routeProvider

.when('/book/index',{

templateUrl:'views/book/index.html',

controller:'index'

})

.when('/book/create',{

templateUrl:'views/book/create.html',

controller:'create',

resolve:{

book:function(services,$route){

returnservices.getBooks();

}

}

})

.when('/book/update/:bookId',{

templateUrl:'views/book/update.html',

controller:'update',

resolve:{

book:function(services,$route){

varbookId=$route.current.params.bookId;

returnservices.getBook(bookId);

}

}

})

.when('/book/delete/:bookId',{

templateUrl:'views/book/index.html',

controller:'delete',

})

.otherwise({

redirectTo:'/book/index'

});

}]);

spaApp_book.controller('index',['$scope','$http','services',

function($scope,$http,services){

$scope.message='EveryonecomeandseehowgoodIlook!';

services.getBooks().then(function(data){

$scope.books=data.data;

});

$scope.deleteBook=function(bookID){

if(confirm("Areyousuretodeletebooknumber:"+bookID)==true&&bookID>0){

services.deleteBook(bookID);

CreateacontrollerforSiteSubModule

HowToCreateSinglePageApplicationinminutes!

21CreateWebClient

$route.reload();

}

};

}])

.controller('create',['$scope','$http','services','$location','book',

function($scope,$http,services,$location,book){

$scope.message='Look!Iamanaboutpage.';

$scope.createBook=function(book){

varresults=services.createBook(book);

}

}])

.controller('update',['$scope','$http','$routeParams','services','$location','book',

function($scope,$http,$routeParams,services,$location,book){

$scope.message='Contactus!JK.Thisisjustademo.';

varoriginal=book.data;

$scope.book=angular.copy(original);

$scope.isClean=function(){

returnangular.equals(original,$scope.book);

}

$scope.updateBook=function(book){

varresults=services.updateBook(book);

}

}]);

Createtemplatefilethatispointedbycontrollerinbooksubmoduleinviewsdirectory.Thenameis

book/index.html:

<div>

<h1>BOOKCRUD</h1>

<p>{{message}}</p>

<divng-show="books.length>0">

<aclass="btnbtn-primary"href="#/book/create">

<iclass="glyphiconglyphicon-plus"></i>Create

</a>

<tableclass="tabletable-stripedtable-hover">

<thead>

<th>Title</th>

<th>Author</th>

<th>Publisher</th>

<th>Year</th>

<thstyle="width:80px;">Action&nbsp;</th>

</thead>

<tbody>

<trng-repeat="datainbooks">

<td>{{data.title}}</td>

<td>{{data.author}}</td>

<td>{{data.publisher}}</td>

<td>{{data.year}}</td>

<td>

<aclass="btnbtn-primarybtn-xs"href="#/book/update/{{data.id}}">

<iclass="glyphiconglyphicon-pencil"></i>

</a>

<aclass="btnbtn-dangerbtn-xs"ng-click="deleteBook(data.id)">

CreateTemplateFileforBookSubModule

HowToCreateSinglePageApplicationinminutes!

22CreateWebClient

<iclass="glyphiconglyphicon-trash"></i>

</a>

</td>

</tr>

</tbody>

</table>

</div>

<divng-show="books.length==0">

Empty

</div>

</div>

Createbook/create.html:

<div>

<h1>BOOKCRUD</h1>

<p>{{message}}</p>

<formrole="form"name="myForm">

<divclass="form-group"ng-class="{error:myForm.title.$invalid}">

<label>Title</label>

<div>

<inputname="title"ng-model="book.title"type="text"class="form-control"

<spanng-show="myForm.title.$dirty&&myForm.title.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group">

<label>Description</label>

<div>

<textareaname="description"ng-model="book.description"class="form-control

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.author.$invalid}">

<label>Author</label>

<div>

<inputname="author"ng-model="book.author"type="text"class="form-control

<spanng-show="myForm.author.$dirty&&myForm.author.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.publisher.$invalid}">

<label>Publisher</label>

<div>

<inputname="publisher"ng-model="book.publisher"type="text"class="form-control

<spanng-show="myForm.publisher.$dirty&&myForm.publisher.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.year.$invalid}">

<label>Year</label>

<div>

<inputname="year"ng-model="book.year"type="text"class="form-control"placeholder

<spanng-show="myForm.year.$dirty&&myForm.year.$invalid"class="help-inline"

</div>

</div>

<ahref="#/book/index"class="btnbtn-default">Cancel</a>

<buttonng-click="createBook(book);"

ng-disabled="myForm.$invalid"

HowToCreateSinglePageApplicationinminutes!

23CreateWebClient

type="submit"class="btnbtn-default">Submit</button>

</form>

</div>

Createbook/update.html:

<div>

<h1>BOOKCRUD</h1>

<p>{{message}}</p>

<formrole="form"name="myForm">

<divclass="form-group"ng-class="{error:myForm.title.$invalid}">

<label>Title</label>

<div>

<inputname="title"ng-model="book.title"type="text"class="form-control"

<spanng-show="myForm.title.$dirty&&myForm.title.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group">

<label>Description</label>

<div>

<textareaname="description"ng-model="book.description"class="form-control

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.author.$invalid}">

<label>Author</label>

<div>

<inputname="author"ng-model="book.author"type="text"class="form-control

<spanng-show="myForm.author.$dirty&&myForm.author.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.publisher.$invalid}">

<label>Publisher</label>

<div>

<inputname="publisher"ng-model="book.publisher"type="text"class="form-control

<spanng-show="myForm.publisher.$dirty&&myForm.publisher.$invalid"class="help-inline"

</div>

</div>

<divclass="form-group"ng-class="{error:myForm.year.$invalid}">

<label>Year</label>

<div>

<inputname="year"ng-model="book.year"type="text"class="form-control"placeholder

<spanng-show="myForm.year.$dirty&&myForm.year.$invalid"class="help-inline"

</div>

</div>

<ahref="#/book/index"class="btnbtn-default">Cancel</a>

<buttonng-click="updateBook(book);"

ng-disabled="isClean()||myForm.$invalid"

type="submit"class="btnbtn-default">Submit</button>

</form>

</div>

ModifyMainMenu

HowToCreateSinglePageApplicationinminutes!

24CreateWebClient

Don'tforgettoaddlinktobookCRUD.

<li><ahref="#/book/index"><iclass="glyphiconglyphicon-book"></i>Book</a></li>

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

Testit

HowToCreateSinglePageApplicationinminutes!

25CreateWebClient

Thispagestillediting.You'reverywelcometocontribute.

Forinstallationassets(javascriptandcss),wecanusebower.Bowerisapackagemanagerforthe

web.It'squitewithcomposerinPHP.

Youshoulddropallfoldersandfilesinsideassetsfolderbeforeusingbower,becausebowerwilldownloadlibrariesforYoubyspecialstructure.

Beforeinstallationbower,wemustinstall:

nodeJs&npmNode.jsisaplatformbuiltonChrome'sJavaScriptruntimeforeasilybuildingfast,scalablenetworkapplications.NPMispackagemanagerforjavascriptGitafreeandopensourcedistributedversioncontrolsystemdesignedtohandleeverythingfromsmalltoverylargeprojectswithspeedandefficiency.

Bowerisacommandlineutility.Installitwithnpm.

npminstall-gbower

Createfilebower.jsoninfolderweb-client

{

"name":"Angular1-Yii2",

"version":"1.0.0",

"homepage":"https://github.com/hscstudio/angular1-yii2",

"description":"AngularJS1.3andYiiFramework2.0",

"dependencies":{

"angular":"~1.3.0",

"bootstrap":"~3.1.1",

"angular-route":"~1.3.0"

}

}

Andthencreatefile.bowerrc,thisfilecontainsconfigurationofbower,addparameterdirectorytospecifytargetfolderinstallation.

Customization

Miscellaneous

Installation

InstallationBower

Usage

HowToCreateSinglePageApplicationinminutes!

26Customization

{

"directory":"assets"

}

Incommandline,dothis

cdweb-client2

bowerinstall

Afterinstallationfinished,Youcanseefolderassetshavecontainedlibraryangular,bootstrap,etc.

Becausestructurefolderthatdownloadedbybowerisdifferent,weshouldadjustlinksjsandcssinfileindex.html.

<!--CSS-->

<linkrel="stylesheet"href="assets/bootstrap/dist/css/bootstrap.min.css"/>

<linkrel="stylesheet"href="assets/bootstrap/dist/css/bootstrap-theme.min.css"/>

<!--JS-->

<scriptsrc="assets/angular/angular.min.js"></script>

<scriptsrc="assets/angular-route/angular-route.min.js"></script>

Thereareseveraltypesofanimationtechniquesthatwecanapplyinourangularjsapplication.ButinthistutorialIwilldiscussabouttheanimationattheturnofthepage.Todothat,weneedthengAnimatemoduletoenableanimationsthroughouttheapplication.

Addmoduleangular-animateinbower.json

{

...

...

"dependencies":{

...

...

"angular-animate":"~1.3.0"

}

}

Andthendo

IncludeinIndex

EnhanceUserInterface

AngularAnimation

HowToCreateSinglePageApplicationinminutes!

27Customization

bowerupdate

Createstyle.cssfordefineanimation,forexample:

.animate.ng-leave{

}

.animate.ng-enter{

-webkit-animation:scaleUp0.5sbothease-in;

-moz-animation:scaleUp0.5sbothease-in;

animation:scaleUp0.5sbothease-in;

}

/*scaleup*/

@keyframesscaleUp{

from{opacity:0.3;transform:scale(0.8);}

}

@-moz-keyframesscaleUp{

from{opacity:0.3;-moz-transform:scale(0.8);}

}

@-webkit-keyframesscaleUp{

from{opacity:0.3;-webkit-transform:scale(0.8);}

}

ng-enter:willattachwhenenteringviewng-leave:whenattachwhenleavingview

Includecssanimationinindex.html:

<linkrel="stylesheet"href="style.css"/>

Addclassanimateinng-view

<divid="main"class="container">

<!--angulartemplating-->

<!--thisiswherecontentwillbeinjected-->

<divng-viewclass="animate"></div>

</div>

IncludemodulengAnimateinapp.js:

varspaApp=angular.module('spaApp',[

'ngRoute',

'spaApp.site',

'spaApp.book',

'ngAnimate'//addmodulengAnimate

]);

HowToCreateSinglePageApplicationinminutes!

28Customization

Forfurtherinformations,readthis:

https://docs.angularjs.org/tutorial/step_12https://docs.angularjs.org/guide/animationshttps://docs.angularjs.org/api/ngAnimate

https://oclazyload.readme.io/v1.0/docs/getting-started

Whenweaddsomemodule,wemustaddincludescriptforsubmoduleinmain.ByusemoduleocLazyLoadwecanmakelazyloadinangular,includeonlywhenneeded.

DownloadocLazyLoad.js(youcaninstallitwithbowerinstalloclazyloadornpminstalloclazyload)andaddthefiletoyourproject.Addthemoduleoc.lazyLoadtoyourapplication:

varspaApp=angular.module('spaApp',[

'ngRoute',

'ngAnimate',

'spaApp.site',

'spaApp.book',

'oc.lazyLoad',//addthismodulelazyLoader

]);

Loadondemand:

spaApp.controller("MyCtrl",function($ocLazyLoad){

$ocLazyLoad.load('testModule.js');

});

With$ocLazyLoadyoucanloadangularmodules,butifyouwanttoloadanycomponent(controllers/services/filters/...)withoutdefininganewmoduleit'sentirelypossible(justmakesurethatyoudefinethiscomponentwithinanexistingmodule).

Therearemultiplewaystouse$ocLazyLoadtoloadyourfiles,justchoosetheonethatyouprefer.

Alsodon'tforgetthatifyouwanttogetstartedandthedocsarenotenough,seetheexamplesinthe'examples'folder!

FlashMessage

AngularLazyLoader

CustomizeRESTfulAPI

Versioning

CustomizeURL

HowToCreateSinglePageApplicationinminutes!

29Customization

Beforewedeployourapplication,weneeddosomethings.

Readofficialguideforapplicationproductionclickhere.

BydefaultAngularJSattachesinformationaboutbindingandscopestoDOMnodes,andaddsCSSclassestodata-boundelements,butwecandisablethisinproductionforasignificantperformanceboostwith:

spaApp.config(['$compileProvider',function($compileProvider){

$compileProvider.debugInfoEnabled(false);

}]);

Usingstrictdimodeinyourproductionapplicationwillthrowerrorswhenainjectablefunctionisnotannotatedexplicitly.Strictdimodeisintendedtohelpyoumakesurethatyourcodewillworkwhenminified.However,italsowillforceyoutomakesurethatyourinjectablefunctionsareexplicitlyannotatedwhichwillimproveangular'sperformancewheninjectingdependenciesinyourinjectablefunctionsbecauseitdoesn'thavetodynamicallydiscoverafunction'sdependencies.Itisrecommendedtoautomatetheexplicitannotationviaatoollikeng-annotatewhenyoudeploytoproduction(andenablestrictdimode)

Toenablestrictdimode,youhavetwooptions:

<divng-app="spaApp"ng-strict-di>

<!--yourapphere-->

</div>

or

angular.bootstrap(document,['spaApp'],{

strictDi:true

});

ErrorHandling

Authorization

HandlingFileUpload

DeployingApplication

WebClient

DisablingDebugData

StrictDIMode

HowToCreateSinglePageApplicationinminutes!

30Customization

SamewithAngularJs,inproductionenvironments,weshoulddisabledebugmode.Itmayhaveasignificantandadverseperformanceeffect,besidesthatthedebugmodemayexposesensitiveinformationtoendusers.

Modifyfileweb/index.phpinweb-service,setYii_DEBUGconsttobefalse,andthenYII_ENVtobe

prod.

defined('YII_DEBUG')ordefine('YII_DEBUG',false);

defined('YII_ENV')ordefine('YII_ENV','prod');

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

WebService

HowToCreateSinglePageApplicationinminutes!

31Customization

Yii2.0makesitmucheasierandfastertoimplementawebserviceaswellasteachingushowtodoitproperly.TheAPIcreatedcouldbeusedeasilyfromAngularJsoranyotherclient.Overall,AngularJSandYii2.0areagoodmatch.

Happycoding!

Jakarta,IndonesiaMay,122015

HafidMukhlasin

BackToIndex01.Introduction02.Preparation03.CreateWebService04.CreateWebClient05.Customization06.Conclusion

Conclusion

http://www.hafidmukhlasin.com

HowToCreateSinglePageApplicationinminutes!

32Conclusion