ساخت یک اپلیکیشن با لاراول و AngularJS – قسمت پایانی
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 15 دقیقه

ساخت یک اپلیکیشن با لاراول و AngularJS – قسمت پایانی

در قسمت قبلی این سری مقاله ها بحث لاراول رو کامل کردیم اینبار میخواهیم بیشتر درمورد نقش Angular در پروژه مون صحبت کنیم. لینک دریافت پروژه

نصب Angular Seed

بیایید با اسکلت بندی بخش client side کار شروع کنیم, برای این کار از angular seed استفاده می کنیم.

ابتدا باید پروژه رو از git دریافت کنید :

git clone https://github.com/angular/angular-seed.git

cd angular-seed

حالا باید وابستگی‌های angular-seed رو دریافت کنیم. برای این کار :

npm install

بعد از انجام اینکار فولدر node_modules و app/bower_components رو در مسیر اصلی پروژه می بینید.

هم لاراول 5 و هم Angularjs بصورت پیشفرض از پورت 8000 استفاده می‌کنند پس ما باید یک پورت دیگه برای یکیشون درنظر بگیریم. بیایید پورت پروژه angular-seed رو عوض کنیم. 

فایل package.json باز کرده و تغییر زیر اعمال کنید :

"start": "http-server -a localhost -p 8080 -c-1"

حالا پروژه رو اجرا کنید :

npm start

حالا به مسیر زیر بروید :

http://localhost:8080/app/index.html

نصب ui-router

پروژه Angular Seed بصورت پیشفرض از router خود angular استفاده می کنه. اما من ui-router رو پیشنهاد میدم. پس ما پروژه خودمون رو به صورت زیر تغییر میدیم. ابتدا اون رو دانلود می‌کنیم :

bower install angular-ui-router –save

در فایل index.html اضافش می‌کنیم :

<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>

حالا ui-router رو به app.js بیافزایید :

angular.module('myApp', [

  // 'ngRoute',

  'ui.router',

  'myApp.view1',

  'myApp.view2'

  'myApp.version'

])

ساخت مسیرهای جدید

دو مسیر می‌سازیم یکی برای auth و دیگری برای jokes. حالا یک مسیر جدید در پوشه app به نام view_auth و view_jokes بسازید. ساختار دایرکتوری به شکل زیر درمیاد :

فایل view_auth/auth.js باز کرده و به شکل زیر آپدیت کنید :

angular.module('myApp.auth', [])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

  $stateProvider

  .state('auth', {

    url: '/auth',

    views: {

      'jokesContent': {

        templateUrl: "view_auth/auth.html",

    controller: 'AuthCtrl as auth'

      }

    }

  })

}])

.controller('AuthCtrl', ['$rootScope', function($rootScope){

}])

حالا فایل view_jokes/jokes.js رو باز کرده و آپدیت کنید :

angular.module('myApp.jokes', [])

.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

  $stateProvider

  .state('jokes', {

    url: '/jokes',

    views: {

      'jokesContent': {

        templateUrl: "view_jokes/jokes.html",

    controller: 'JokesCtrl as jokes'

      }

    }

  })

}])

.controller('JokesCtrl', ['$rootScope', function($rootScope){

}])



فایلهای view_auth/auth.html و view_jokes/jokes.html باز کرده و یکسری محتوا اضافه کنید. 

و فایلهای اسکریپت رو به index.html اضافه کنید :

<script src="view_auth/auth.js"></script>

<script src="view_jokes/jokes.js"></script>

حالا وابستگی‌های app.js رو به روز کنید :

// Declare app level module which depends on views, and components

angular.module('myApp', [

  // 'ngRoute',

  'ui.router',

  'myApp.jokes',

  'myApp.view2',

  'myApp.auth',

  'myApp.version'

])

میتونید مسیرها رو در مرورگر مشاهده کنید :

http://localhost:8080/app/#/auth

,

http://localhost:8080/app/#/jokes

تأیید اعتبار Clinet Side

فایل view_auth/auth.html رو باز کرده و کد زیر رو بیافزایید :

<div class="container">

    <div class="row">

        <div class="col-md-4 col-md-offset-4">

            <div class="panel panel-default">

                <div class="panel-heading"> <strong class="">Login</strong>



                </div>

                <div class="panel-body">

                    <form class="form-horizontal" role="form">

                        <div class="form-group">

                            <label for="inputEmail3" class="col-sm-3 control-label">Email</label>

                            <div class="col-sm-9">

                                <input type="email" class="form-control" id="inputEmail3" placeholder="Email" required="" ng-model="auth.email">

                            </div>

                        </div>

                        <div class="form-group">

                            <label for="inputPassword3" class="col-sm-3 control-label">Password</label>

                            <div class="col-sm-9">

                                <input type="password" class="form-control" id="inputPassword3" placeholder="Password" required="" ng-model="auth.password">

                            </div>

                        </div>

                        <div class="form-group last">

                            <div class="col-sm-offset-3 col-sm-9">

                                <button type="submit" class="btn btn-success btn-sm"  ng-click="auth.login()">Sign in</button>

                                <button type="reset" class="btn btn-default btn-sm">Reset</button>

                            </div>

                        </div>

                    </form>

                </div>

            </div>

        </div>

    </div>

</div>

خروجی به صورت زیر می‌شود :

استفاده از Satellizer 

حالا برای تأیید اعتبار client side ما از یک سیستم token base به نام satellizer استفاده می کنیم.

bower install satellizer –save

فایل satellizer.js رو به index.html اضافه کنید :

<script src="bower_components/satellizer/satellizer.js"></script>

اون رو به لیست وابستگی‌های app.js اضافه کنید :

angular.module('myApp', [

  // 'ngRoute',

  'ui.router',

  'myApp.jokes',

  'myApp.view2',

  'myApp.auth',

  'myApp.version',

   'satellizer'

])

و کانفیگ login رو در app.js وارد کنید :

.config(['$stateProvider', '$urlRouterProvider', '$authProvider', function($stateProvider, $urlRouterProvider, $authProvider) {



$authProvider.loginUrl = 'http://localhost:8000/api/v1/authenticate';

  // $urlRouterProvider.otherwise('/view1');

  $urlRouterProvider.otherwise('/auth');

}]);

این کتابخانه به شما دسترسی به authProvider$ میده. ما میدونیم که برای api لاراول هربار نیاز به توکن داریم این کتابخانه به ما اطمینان میده با هر درخواست توکن هم بصورت خودکار فرستاده بشه. 

فایل view_auth/auth.js رو باز کرده و کنترلر رو به شکل زیر تغییر بدید :

.controller('AuthCtrl', ['$auth', '$state', '$http', '$rootScope', function($auth, $state, $http, $rootScope) {
      var vm = this;

        vm.loginError = false;

        vm.loginErrorText;


        vm.login = function() {

            var credentials = {

                email: vm.email,

                password: vm.password

            }


            $auth.login(credentials).then(function() {

                $http.get('http://localhost:8000/api/v1/authenticate/user').success(function(response){

                    var user = JSON.stringify(response.user);

                    localStorage.setItem('user', user);

                    $rootScope.currentUser = response.user;                   

                    $state.go('jokes');

                })

                .error(function(){

                    vm.loginError = true;

                    vm.loginErrorText = error.data.error;

                    console.log(vm.loginErrorText);

                })

            });

        }

حالا بعد از شروع سرور لاراول مسیر auth باز کنید و بعد از وارد کردن اطلاعات کاربری دکمه ثبت رو بزنید. شما آیتم های زیر رو می‌بینید که به حافظه محلی اضافه شده :

دریافت تمام جوک ها

فایل view_jokes/jokes.html باز کنید و بصورت زیر تغییر بدید :

<div class="col-sm-6 col-sm-offset-3">

        <div>

        <ul class="list-group">

            <li class="list-group-item" ng-repeat="joke in jokes.jokes">

                <h5>{{joke.joke}}</h5>

                <h5>{{joke.submitted_by}}</h5>

            </li>

        </ul>

        <div class="alert alert-danger" ng-if="jokes.error">

            <strong>There was an error: </strong> {{jokes.error}}

            <br>Please go back and login again...

        </div>

    </div>

</div>

حالا view_jokes/jokes.js باز کنید و بصورت زیر دربیارید :

.controller('JokesCtrl', ['$http', '$auth', '$rootScope','$state', '$q' , function($http, $auth, $rootScope, $state, $q) {

  var vm = this;        

  vm.jokes = [];

  vm.error;

  vm.joke;

  $http.get('http://localhost:8000/api/v1/jokes').success(function(jokes){    

    console.log(jokes);

    vm.jokes = jokes.data;

    }).error(function(error){

      vm.error = error;

    })

  vm.init();


}]);

من میتونم بخش زیادی از کد رو به factory یا service ببرم اما برای راحتی کار این رو انجام نمیدم.

حالا اگر مسیر jokes رو باز کنید :

آراستن اپلیکیشن و بخش خروج از حساب

فایل index.html باز کرده و کد container رو آپدیت کنید :

<div class="container">

        <nav class="navbar navbar-default">

          <div class="container-fluid">

            <!-- Brand and toggle get grouped for better mobile display -->

            <div class="navbar-header">

              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">

                <span class="sr-only">Toggle navigation</span>

                <span class="icon-bar"></span>

                <span class="icon-bar"></span>

                <span class="icon-bar"></span>

              </button>

              <a class="navbar-brand" href="">Jokes App</a>

            </div>



            <!-- Collect the nav links, forms, and other content for toggling -->

            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">

              <ul class="nav navbar-nav">

                <li><a ui-sref="auth">Auth</a></li>

                <li><a ui-sref="jokes">Jokes</a></li>

              </ul>

              <ul class="nav navbar-nav navbar-right" ng-show="currentUser != null">

              <li><a href="">Welcome, {{currentUser.name}}</a></li>

                <li class="dropdown">

                  <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">My Profile <span class="caret"></span></a>

                  <ul class="dropdown-menu">

                    <li><a ng-click="logout()" style="cursor: pointer;">Logout</a></li>

                  </ul>

                </li>

              </ul>

            </div><!-- /.navbar-collapse -->

          </div><!-- /.container-fluid -->

        </nav>





        <div ui-view="jokesContent"></div>

    </div>

حالا فایل app.js رو باز کرده و کد logout رو اضافه کنید :

.run(function ($rootScope, $state, $auth) {



      $rootScope.logout = function() {

        $auth.logout().then(function() {

            localStorage.removeItem('user');

            $rootScope.currentUser = null;

            $state.go('auth');

            });

           }

         })

$rootScope.currentUser = JSON.parse(localStorage.getItem('user'));

}

حالا logout – خروج از حساب – کار می کنه.

امن سازی مسیرها

هم‌اکنون اگر کسی تأیید هویت شده باشه هنوز به مسیر auth دسترسی داره برای جلوگیری از این باگ ها از پکیج angular-permission بهره می بریم. 

bower install angular-permission –save

آپدیت app.js

angular.module('myApp', [

  // 'ngRoute',

  'ui.router',

  'myApp.jokes',

  'myApp.view2',

  'myApp.auth',

  'myApp.version',

   'satellizer',

   'permission'

])


کانفیگ فایل view_auth/auth.js :

.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

  $stateProvider

  .state('auth', {

    url: '/auth',

    data: {

        permissions: {

          except: ['isloggedin'],

          redirectTo: 'jokes'

        }

      },

    views: {

      'jokesContent': {

        templateUrl: "view_auth/auth.html",

    controller: 'AuthCtrl as auth'

      }

    }

  })

}])

با استفاده از نقش isloggedin این مسیر برای کاربران وارد نشده قابل دسترس میشه.

برای تعریف نقش در run function - app.js :

Permission 

     .defineRole('isloggedin', function (stateParams) {

        // If the returned value is *truthy* then the user has the role, otherwise they don't

        // console.log("isloggedin ", $auth.isAuthenticated()); 

        if ($auth.isAuthenticated()) {

          return true; // Is loggedin

        }

        return false;

      })

فایل view_jokes/jokes.js :

.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

  $stateProvider

  .state('jokes', {

    url: '/jokes',

    data: {

        permissions: {

          except: ['anonymous'],

          redirectTo: 'auth'

        }

      },

    views: {

      'jokesContent': {

        templateUrl: "view_jokes/jokes.html",

    controller: 'JokesCtrl as jokes'

      }

    }

  })

}])

و تعریف نقش افراد ناشناس در app.js run function :

// Define anonymous role

      Permission

      .defineRole('anonymous', function (stateParams) {

        // If the returned value is *truthy* then the user has the role, otherwise they don't

        // var User = JSON.parse(localStorage.getItem('user')); 

        // console.log("anonymous ", $auth.isAuthenticated()); 

        if (!$auth.isAuthenticated()) {

          return true; // Is anonymous

        }

        return false;

      })



      .defineRole('isloggedin', function (stateParams) {

        // If the returned value is *truthy* then the user has the role, otherwise they don't

        // console.log("isloggedin ", $auth.isAuthenticated()); 

        if ($auth.isAuthenticated()) {

          return true; // Is loggedin

        }

        return false;

      })

      ;

درخواست های POST, UPDATE, DELETE

فایل view_jokes/jokes.html :

<div class="col-sm-6 col-sm-offset-3">

        <div class="row">

            <div class="col-sm-12">

                <div class="input-group">

                  <input type="text" class="form-control" placeholder="Add new joke.." ng-model="jokes.joke">

                  <span class="input-group-btn">

                    <button class="btn btn-default" type="button" ng-click="jokes.addJoke()">Add!</button>

                  </span>

                </div><!-- /input-group -->

              </div><!-- /.col-lg-6 -->

        </div>

        <br>

        <div>

        <ul class="list-group">

            <li class="list-group-item" ng-repeat="joke in jokes.jokes">

                <span ng-hide="editEnabled">

                            {{joke.joke}}

                                <a href="#" ng-click="editEnabled=!editEnabled"><span class="glyphicon glyphicon-pencil" ></span></a>

                </span>

                <span ng-show="editEnabled">

                            <input ng-model="joke.joke">

                            <a href="#" ng-click="editEnabled=!editEnabled; jokes.updateJoke(joke)"><span class="glyphicon glyphicon-ok" ></span></a>

                </span>

                <!-- <h4>{{joke.joke}}</h4> -->

                <span style="cursor: pointer;" class="glyphicon glyphicon-trash" ng-click="jokes.deleteJoke($index, joke.joke_id)"></span>

                <h5>{{joke.submitted_by}}</h5>

            </li>

        </ul>

        <div class="alert alert-danger" ng-if="jokes.error">

            <strong>There was an error: </strong> {{jokes.error}}

            <br>Please go back and login again...

        </div>

    </div>

</div>

و فایل view_jokes/jokes.js :

.controller('JokesCtrl', ['$http', '$auth', '$rootScope','$state', '$q' , function($http, $auth, $rootScope, $state, $q) {


  var vm = this;
        

  vm.jokes = [];

  vm.error;

  vm.joke;



  $http.get('http://localhost:8000/api/v1/jokes').success(function(jokes){    

    console.log(jokes);

    vm.jokes = jokes.data;

    }).error(function(error){

      vm.error = error;

    })            


    vm.addJoke = function() {

        $http.post('http://localhost:8000/api/v1/jokes', {

            body: vm.joke,

            user_id: $rootScope.currentUser.id

        }).success(function(response) {

            // console.log(vm.jokes);

            // vm.jokes.push(response.data);

            vm.jokes.unshift(response.data);

            console.log(vm.jokes);

            vm.joke = '';

            // alert(data.message);

            // alert("Joke Created Successfully");

        }).error(function(){

          console.log("error");

        });

    };

    vm.updateJoke = function(joke){

      console.log(joke);

      $http.put('http://localhost:8000/api/v1/jokes/' + joke.joke_id, {

            body: joke.joke,

            user_id: $rootScope.currentUser.id

        }).success(function(response) {

            // alert("Joke Updated Successfully");

        }).error(function(){

          console.log("error");

        });

    }

    vm.deleteJoke = function(index, jokeId){

      console.log(index, jokeId);



        $http.delete('http://localhost:8000/api/v1/jokes/' + jokeId)

            .success(function() {

                vm.jokes.splice(index, 1);

            });;

    }

}]);

میتونید عملیات های ADD, UPDATE, DELETE رو به راحتی انجام بدید.

صفحه بندی

ما میخواهیم یک دکمه بارگزاری بیشتر قرار بدیم. این دکمه رو در view_jokes/jokes.html :

<button class="btn btn-success" ng-click="jokes.loadMore()" style="float:right">Load More....</button>

فایل view_jokes/jokes.js :


// $http.get('http://localhost:8000/api/v1/jokes').success(function(jokes){    

  //   console.log(jokes);

  //   vm.jokes = jokes.data;

  //   }).error(function(error){

  //     vm.error = error;

  //   })

  
  vm.lastpage=1;

  vm.init = function() {

                vm.lastpage=1;

                $http({

                    url: 'http://localhost:8000/api/v1/jokes',

                    method: "GET",

                    params: {page:  vm.lastpage}

                }).success(function(jokes, status, headers, config) {

                    vm.jokes = jokes.data;

                    vm.currentpage = jokes.current_page;

                });

            };

  vm.init();

  vm.loadMore = function() {

                vm.lastpage +=1;

                $http({

                    url: 'http://localhost:8000/api/v1/jokes',

                    method: "GET",

                    params: {page:  vm.lastpage}

                }).success(function (jokes, status, headers, config) {



                    vm.jokes = vm.jokes.concat(jokes.data);



                });

            };

حالا بیایید کد رو تست کنیم :

تبریک میگم api لاراول شما به همراه client side با تکنولوژی AngularJS تکمیل شد! 

دانلود پروژه

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
در انتظار ثبت رای

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید