ui-routerとcodeigniterを組み合わせてSPAをつくるときのメモ
できるまで色々と試行錯誤して大変だったからメモする。
環境
angular.version.full "1.3.15"
codeigniter define('CI_VERSION', '2.0.3');
やりたいこと
SPAというものを試してみたかったので、お手軽にcodeIgniterとangularで作ってみよう
調べてみて
angularにはデフォルトにng-routeというものがデフォルトであったが、 angular-ui-routerの方ができることの幅が広く、評判もよかったのでそっちを使うことにした
やり方
- SPA用のページテンプレートを作成
controller、viewに下記のようにテンプレートを作成する
controllers/ang.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Ang extends CI_Controller { public function index() { $this->load->view('ang/index'); } public function template1() { $this->load->view('ang/template1'); } public function template2() { $this->load->view('ang/template2'); } }
views/ang/index.html
<base href="<?= base_url(); ?>"> <!doctype html> <html ng-app="app"> <head> <meta charset="utf-8"> <title></title> <meta name="description" content=""> <meta name="viewport" content="width=device-width"> <script src="js/bower_components/angular/angular.min.js"></script> <script src="js/bower_components/angular-ui-router/release/angular-ui-router.js"></script> <script src="js/ang/app.js"></script> </head> <body> <h3>ui.router</h3> <p>ui-routerでそれぞれpageを指定してみた</p> <div ng-controller="MainCtrl"> <!-- multiple ページバージョン --> <a ui-sref="contacts_state">template1を読み込む</a> <a ui-sref="question_state">template2を読み込む</a> <section ui-view><i>templateが読み込まれる</i></section> </div> </body> </html>
views/ang/template1.php
template1読み込みok!!! <br /> {{title}}
views/ang/template2.php
template2読み込みok!!! <br /> {{title}}
- js部分をつくる
js/ang/app.js
'use strict'; var app = angular.module('app', ['ui.router']) .config(['$stateProvider', function($stateProvider){ $stateProvider .state('contacts_state', { url: '/contacts', templateUrl: 'ang/template1', controller: function($scope) { $scope.title = 'contactsに入りました!'; } }) .state('question_state', { url: '/question', templateUrl: 'ang/template2', controller: function($scope) { $scope.title = 'questionに入りました!'; } }) }]);
わかったこと
codeigniter側では、きちんとコントローラーとviewをセットしてあげないとだめ。 angular側でうまくやるのかと勘違いしていたが、結局URLを参照するから セットしないと何も起きなくなる。
app.jsにstateを記述する。 その際例でいうと、contacts_stateがstate名になり、 index.htmlのように
<a ui-sref="contacts_state">template1を読み込む</a>
のようにすると、クリックするとURLが#/contactsにかわり<a ui-sref="contacts_state">template1を読み込む</a>
にang/template1が挿入されるapp.jsのcontroller. function($scope)・・・ のように記載すると各種ページの中でその$scopeがつかえる
その他試したこと
デフォルトルートと引数
views/ang/index.html
<a ui-sref="detail({empId:12345})">template7へ遷移</a> <div id="template"> <section ui-view><i>templateが読み込まれる</i></section> </div>
js/ang/app.js
'use strict'; var app = angular.module('app4', ['ui.router']) .config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){ $stateProvider .state('detail', { url: '/detail/{empId:[0-9]{5}}', templateUrl: 'ang/template7', controller: function($stateParams, $scope) { $scope.empId = $stateParams.empId; $scope.title = 'detailに入りました!'; } }) .state('error_state', { url: '/error', templateUrl: 'ang/template_error', controller: function($scope) { $scope.error = 'errorだよ'; } }); $urlRouterProvider .otherwise('/error'); }]) .controller('MainCtrl', ['$scope', function($scope){ $scope.context = 'year!!'; }]);
- 上記の$urlRouterProviderのように定義すれば、指定URL以外は/errorに飛ばすことができる (stateに定義を忘れずに)
- URLに引数を指定させる場合はdetail部分のように正規表現をつかえる
- 引数の取得は$scope.empIdのように取得する
ui-viewに名前をつける
views/ang/index.html
<a ui-sref="contacts">template2とtemplate4を読み込む</a> <a ui-sref="question">template3を読み込む</a> <section ui-view="main"><i>template2が読み込まれる</i></section> <section ui-view="main2"><i>template2が読み込まれる</i></section> <section ui-view="sub"><i>template3が読み込まれる</i></section>
js/ang/app.js
'use strict'; var app = angular.module('app2', ['ui.router']) .config(['$stateProvider', function($stateProvider){ $stateProvider .state('contacts', { views: { "main" : { url: '/contacts', templateUrl: 'ang/template2', controller: function($scope) { $scope.title = 'contactsに入りました!'; } }, "main2" : { url: '/contacts', templateUrl: 'ang/template4', controller: function($scope) { $scope.title = 'contactsに入りました!'; } } } }) .state('question', { views: { "sub" : { url: '/question', templateUrl: 'ang/template3', controller: function($scope) { $scope.title = 'questionに入りました!'; } } } }) }]);
上記のように定義すればui-viewに名前を指定できる。
ただし、
- URLを変更できない。
- 同時に2つ以上のviewを呼び出せない。
だった。(僕のやり方が悪い?)
angularは覚えることが多いけど、面白い機能がいっぱいなので、もっと勉強しよう。