Статьи

Создание приложения AngularJS на основе Python EVE: Часть 2

В предыдущей части этой серии мы реализовали процесс входа и регистрации, используя Eve API, который мы создали в первой части серии. Мы использовали Node.js и AngularJS для создания и запуска нашего приложения.

В этом руководстве мы выведем нашу разработку приложений на новый уровень, используя API Add , Edit и Delete для создания элементов на домашней странице пользователя.

Для начала клонируйте исходный код предыдущего урока из GitHub .

1
git clone https://github.com/jay3dec/AngularEveApp_Part1.git

После этого перейдите к AngularEveApp_Part1 и установите зависимости.

1
2
npm install
bower install

Убедитесь, что REST API Python Eve работают. Запустите сервер приложений.

1
node app.js

Укажите в браузере http: // localhost: 3000, и приложение должно быть запущено.

После того, как пользователь успешно войдет в систему, мы перенесем его на главную страницу Итак, начнем с создания userHome.html . Перейдите в userHome папку и создайте новую папку с именем userHome . Внутри userHome создайте файлы с userHome.html и userHome.js . Откройте userHome.html и добавьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<div class=»container»>
    <div class=»header»>
        <nav>
            <ul class=»nav nav-pills pull-right»>
                <li role=»presentation» class=»active»><a href=»#userHome»>Home</a></li>
                <li role=»presentation»><a href=»#addItem»>Add</a></li>
                <li role=»presentation»><a href=»#»>Logout</a></li>
            </ul>
        </nav>
        <h3 class=»text-muted»>Home</h3>
    </div>
    <h1>Data will be displayed here !!</h1>
 
    <footer class=»footer»>
        <p>&copy;
    </footer>
 
</div>

Внутри userHome.js определите модуль userHome его шаблон и контроллер. Итак, откройте userHome.js и добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
‘use strict’;
 
angular.module(‘userHome’, [‘ngRoute’])
 
.config([‘$routeProvider’, function($routeProvider) {
    $routeProvider.when(‘/userHome’, {
        templateUrl: ‘../userHome/userHome.html’,
        controller: ‘UserHomeCtrl’
    });
}])
 
.controller(‘UserHomeCtrl’, [‘$scope’, function($scope) {
 
}]);

Добавьте ссылку на userHome.js на странице index.html .

1
<script src=»userHome/userHome.js»></script>

userHome модуль userHome в приложение myApp в index.js .

1
2
3
4
5
6
7
8
9
angular.module(‘myApp’, [
  ‘ngRoute’,
  ‘home’,
  ‘signin’,
  ‘userHome’
]).
config([‘$routeProvider’, function($routeProvider) {
  $routeProvider.otherwise({redirectTo: ‘/home’});
}]);

В функции signIn в signin.js при signin.js запроса $http перенаправьте в представление /userHome .

1
$location.path(‘/userHome’);

Сохраните вышеуказанные изменения и перезапустите сервер узла. Укажите в браузере http: // localhost: 3000 и войдите в систему, используя действительное имя пользователя и пароль. После успешного входа вы сможете просматривать домашнюю страницу пользователя с видом по умолчанию.

Домашняя страница пользователя с видом по умолчанию

Давайте добавим представление, чтобы позволить пользователю добавлять элементы. Перейдите в addItem папку и создайте папку с именем addItem . Внутри папки addItem создайте два файла с addItem.html и addItem.js . Откройте addItem.html и добавьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div class=»container»>
    <div class=»header»>
        <nav>
            <ul class=»nav nav-pills pull-right»>
                <li role=»presentation»><a href=»#userHome»>Home</a></li>
                <li role=»presentation» class=»active»><a href=»#addItem»>Add</a></li>
                <li role=»presentation»><a href=»#»>Logout</a></li>
            </ul>
        </nav>
        <h3 class=»text-muted»>Home</h3>
    </div>
 
 
    <div class=»row»>
 
        <div class=»col-md-8 col-sm-8 col-xs-8″>
            <input id=»txtTitle» name=»txtTitle» type=»text» ng-model=»title» placeholder=»Enter Task» class=»form-control input-md»>
        </div>
 
        <div class=»col-md-4 col-sm-4 col-xs-4″>
            <input id=»singlebutton» name=»singlebutton» class=»btn btn-primary» ng-click=»addItem(title)» value=»Add Task» />
        </div>
 
 
    </div>
 
 
    <footer class=»footer»>
        <p>&copy;
    </footer>
 
</div>

Затем откройте addItem.js и добавьте следующий код, чтобы определить маршрут, шаблон и контроллер.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
‘use strict’;
 
angular.module(‘addItem’, [‘ngRoute’])
 
.config([‘$routeProvider’, function($routeProvider) {
  $routeProvider.when(‘/addItem’, {
    templateUrl: ‘../addItem/addItem.html’,
    controller: ‘AddItemCtrl’
  });
}])
 
.controller(‘AddItemCtrl’, [function() {
 
}]);

Откройте userHome.html и измените ссылку Добавить ссылку, чтобы указать правильный маршрут.

1
<li role=»presentation» ><a href=»#addItem»>Add</a></li>

Добавьте ссылку на addItem.js в index.html .

1
<script src=»addItem/addItem.js»></script>

addItem модуль addItem в myApp в index.js .

01
02
03
04
05
06
07
08
09
10
angular.module(‘myApp’, [
  ‘ngRoute’,
  ‘home’,
  ‘signin’,
  ‘userHome’,
  ‘addItem’
]).
config([‘$routeProvider’, function($routeProvider) {
  $routeProvider.otherwise({redirectTo: ‘/home’});
}]);

Сохраните следующие изменения и перезапустите сервер узла. После того, как вы вошли в систему, нажмите на ссылку Добавить, и вы сможете увидеть страницу добавления элемента.

Добавить страницу

Для добавления элементов нам понадобятся authdata base64 . Таким образом, при успешном входе мы сохраним имя пользователя и данные AngularJS службе AngularJS . Перейдите в public папку и создайте папку с именем service . Внутри service папки создайте файл с именем service.js . Давайте создадим новый сервисный модуль под названием myAppService .

1
angular.module(‘myAppService’,[])

Добавьте новый сервис в модуль myAppService .

1
2
3
.service(‘CommonProp’, function() {
 
});

Внутри сервиса CommonProp мы определим несколько функций для получения и установки имени username и authData .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
.service(‘CommonProp’, function() {
    var user = »;
    var userAuth = »;
 
    return {
        getUser: function() {
            return user;
        },
        setUser: function(value) {
            user = value;
        },
        getUserAuth: function() {
            return userAuth;
        },
        setUserAuth: function(value) {
            userAuth = value;
        }
    };
});

Включить ссылку на сервис в index.html .

1
<script src=»service/service.js»></script>

Затем myAppService созданный myAppService модуль signin модуль signin .

1
angular.module(‘signin’, [‘base64′,’ngRoute’,’myAppService’])

CommonProp необходимую службу SignInCtrl контроллер SignInCtrl .

1
.controller(‘SignInCtrl’,[‘$scope’,’$http’,’$base64′,’$window’,’$location’,’CommonProp’,function($scope,$http,$base64,$window,$location,CommonProp)

При $http вызове $http success добавьте следующий код, чтобы сохранить имя пользователя и authData в службе.

1
2
CommonProp.setUser(username);
CommonProp.setUserAuth(authdata);

Затем откройте addItem.js и myAppService модуль myAppService .

1
angular.module(‘addItem’, [‘ngRoute’,’myAppService’])

CommonProp службу CommonProp в AddItemCtrl .

1
.controller(‘AddItemCtrl’, [‘$scope’,’CommonProp’,’$http’,’$location’,function($scope,CommonProp,$http,$location)

Откройте addItem.html ngModel и ngClick директивы ngModel и ngClick в текстовое поле задачи и кнопку «Добавить задачу» соответственно.

1
2
3
4
5
6
7
<div class=»col-md-8 col-sm-8 col-xs-8″>
  <input id=»txtTitle» name=»txtTitle» type=»text» ng-model=»title» placeholder=»Enter Task» class=»form-control input-md»>
</div>
 
<div class=»col-md-4 col-sm-4 col-xs-4″>
  <input id=»singlebutton» name=»singlebutton» class=»btn btn-primary» ng-click=»addItem(title)» value=»Add Task» />
</div>

Внутри addItem.js определите новую функцию с именем addItem .

1
2
3
$scope.addItem = function(title){
    // Add item logic will be here !
}

Внутри функции addItem давайте сделаем наш вызов $http для API REST Python Eve. Сначала нам нужно получить имя пользователя и данные аутентификации пользователя из сервиса.

1
2
3
var auth = CommonProp.getUserAuth();
     
var user = CommonProp.getUser();

Давайте установим необходимые заголовки для вызова API.

1
2
3
4
5
$http.defaults.headers.common = {«Access-Control-Request-Headers»: «accept, origin, authorization»};
$http.defaults.headers.common = {«Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»};
$http.defaults.headers.common[«Cache-Control»] = «no-cache»;
$http.defaults.headers.common.Pragma = «no-cache»;
$http.defaults.headers.common[‘Authorization’] = ‘Basic ‘+auth;

После того, как заголовки установлены, давайте используем $http чтобы сделать вызов API для добавления элемента.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
$http({
    method: ‘POST’,
    cache: false,
    url: ‘http://127.0.0.1:5000/item’,
    data: {
        name: title,
        username: user
    }
}).
success(function(data, status, headers, config) {
    $location.path(‘/userHome’);
}).
error(function(data, status, headers, config) {
    console.log(data, status);
});

Сохраните изменения и перезапустите сервер узла. В браузере укажите http: // localhost: 3000 и войдите в систему. Нажмите на ссылку « Добавить» , введите задачу и нажмите « Добавить задачу» . При успешном вызове API вы должны быть перенаправлены на домашнюю страницу пользователя.

Когда домашняя страница пользователя загружена, мы сделаем вызов API, чтобы получить элементы, добавленные конкретным пользователем. Для вызова API нам потребуются username и authData . Итак, myAppService модуль userHome модуль userHome .

1
angular.module(‘userHome’, [‘ngRoute’,’myAppService’])

CommonProp сервис UserHomeCtrl в UserHomeCtrl .

1
.controller(‘UserHomeCtrl’,[‘$scope’,’CommonProp’,’$http’,’$location’, function($scope,CommonProp,$http,$location)

Далее, давайте CommonProp username и authData из CommonProp .

1
2
3
var auth = CommonProp.getUserAuth();
     
var user = CommonProp.getUser();

Установите необходимые заголовки для вызова API.

1
2
3
4
5
$http.defaults.headers.common = {«Access-Control-Request-Headers»: «accept, origin, authorization»};
$http.defaults.headers.common = {«Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»};
$http.defaults.headers.common[«Cache-Control»] = «no-cache»;
$http.defaults.headers.common.Pragma = «no-cache»;
$http.defaults.headers.common[‘Authorization’] = ‘Basic ‘+auth;

Чтобы получить задачи, созданные конкретным пользователем, мы сделаем запрос $ http GET по адресу http://127.0.0.1:5000/item?where= average»username»:» ‘+user+ ‘»} ‘.

01
02
03
04
05
06
07
08
09
10
11
$http({
    method: ‘GET’,
    cache: false,
    url: ‘http://127.0.0.1:5000/item?where={«username»:»‘ + user + ‘»}’
}).
success(function(data, status, headers, config) {
    console.log(data);
}).
error(function(data, status, headers, config) {
    console.log(data, status);
});

При успешном вызове API мы проанализируем возвращенные данные и установим данные в переменную $scope .

Во-первых, давайте создадим переменную задач:

1
$scope.tasks = [];

Теперь давайте проанализируем возвращенные данные и заполним переменную tasks .

1
2
3
4
5
for (var i = 0; i < data._items.length; i++) {
    $scope.tasks.push({
        ‘title’: data._items[i].name
    });
}

В userHome.html мы будем перебирать переменную tasks и отображать задачи, выбранные для конкретного пользователя. Мы будем использовать директиву ngRepeat для перебора переменных задач.

1
2
3
4
5
6
7
<div class=»list-group» ng-repeat=»task in tasks»>
    <a href=»#» onclick=»return false;»
 
        <p class=»list-group-item-text»>{{task.title}}</p>
 
    </a>
</div>

Сохраните вышеуказанные изменения и перезагрузите сервер. В браузере укажите http: // localhost: 3000 и войдите в систему. При успешном входе в систему вы сможете увидеть задачи, добавленные зарегистрированным пользователем.

Дом пользователя с перечисленными задачами

Давайте добавим кнопку редактирования и удаления в список задач на домашней странице пользователя, чтобы включить редактирование и удаление задач соответственно. Откройте userHome.html и добавьте следующий HTML-код в div .list-group .

1
2
3
4
5
<span class=»pull-right»>
     <button class=»btn btn-xs btn-info» ng-click=»editTask(task.title,task.id,task.tag)» data-target=»#editModal»>EDIT</button>
      
     <button class=»btn btn-xs btn-warning» ng-click=»confirmDelete(task.id,task.tag)» data-target=»#deleteModal» >DELETE</button>

Мы будем использовать загрузочные модалы, чтобы показать задачу, которую нужно отредактировать, поэтому включите jQuery и Bootstrap в index.html .

1
2
3
<script src=»https://code.jquery.com/jquery-2.0.1.min.js»></script>
  
<script src=»https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js»></script>

Добавьте следующий HTML-код в userHome.html для модального всплывающего окна для редактирования.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class=»modal fade» id=»editModal» tabindex=»-1″ role=»dialog» aria-labelledby=»editModalLabel» aria-hidden=»true»>
    <div class=»modal-dialog»>
        <div class=»modal-content»>
            <div class=»modal-header»>
                <button type=»button» class=»close» data-dismiss=»modal»><span aria-hidden=»true»>&times;
                </button>
                <h4 class=»modal-title» id=»editModalLabel»>Update Task</h4>
            </div>
            <div class=»modal-body»>
                <form role=»form»>
                    <div class=»form-group»>
                        <label for=»recipient-name» class=»control-label»>Title:</label>
                        <input type=»text» class=»form-control» ng-model=»edit.task» id=»recipient-name»>
                    </div>
                </form>
            </div>
            <div class=»modal-footer»>
                <button type=»button» class=»btn btn-default» data-dismiss=»modal»>Close</button>
                <button type=»button» class=»btn btn-primary» ng-click=»update()»>Update</button>
            </div>
        </div>
    </div>
</div>

Затем откройте userHome.js и создайте новую функцию с именем editTask которая будет вызываться при нажатии кнопки редактирования.

1
2
3
4
5
6
7
8
$scope.edit = {};
 
$scope.editTask = function(title,id,tag){
        $scope.edit.task = title;
        $scope.edit.id = id;
        $scope.edit.tag = tag;
        $(‘#editModal’).modal(‘show’);
}

Как видно из приведенного выше кода, мы присвоили title , id и tag конкретной записи переменной $scope.edit.task . Если пользователь решит обновить конкретную запись, мы будем использовать данные $scope.edit для обновления.

Сохраните все вышеперечисленные изменения и перезагрузите сервер. После успешного входа в систему нажмите кнопку редактирования, чтобы отредактировать задачу, и у вас должно появиться модальное всплывающее окно.

Обновление задачи всплывающего окна

Ранее мы сделали запрос $http от UserHomeCtrl . Давайте преобразуем это в правильную функцию, так как нам нужно будет вызывать это в будущем. Вот функция getAllTask .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
var getAllTask = function(){
        $scope.tasks = [];
        $http.defaults.headers.common = {«Access-Control-Request-Headers»: «accept, origin, authorization»};
        $http.defaults.headers.common = {«Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»};
        $http.defaults.headers.common[«Cache-Control»] = «no-cache»;
        $http.defaults.headers.common.Pragma = «no-cache»;
        $http.defaults.headers.common[‘Authorization’] = ‘Basic ‘+auth;
         
        $http({method: ‘GET’,cache: false, url: ‘http://127.0.0.1:5000/item?where={«username»:»‘+user+’»}’}).
            success(function(data, status, headers, config) {
         
            for(var i=0;i<data._items.length;i++){
                $scope.tasks.push({‘title’: data._items[i].name,’id’:data._items[i]._id,’tag’:data._items[i]._etag});
            }
             
            }).
            error(function(data, status, headers, config) {
                console.log(data,status);
            });
}
 
getAllTask();

Затем создайте функцию с именем update в userHome.js которую мы будем вызывать для обновления отредактированной задачи. Внутри функции обновления мы сделаем запрос PATCH на http://127.0.0.1:5000/item/(item-id) с данными, которые будут обновлены. Eve API ожидает, что заголовок tag id будет передан при выполнении запроса на обновление, поэтому мы также tag id в заголовок запроса. Внутри функции обновления сначала мы объявим требуемые заголовки для запроса $http .

1
2
3
4
5
6
$http.defaults.headers.common = {«Access-Control-Request-Headers»: «accept, origin, authorization»};
$http.defaults.headers.common = {«Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»};
$http.defaults.headers.common[«Cache-Control»] = «no-cache»;
$http.defaults.headers.common.Pragma = «no-cache»;
$http.defaults.headers.common[‘Authorization’] = ‘Basic ‘+auth;
$http.defaults.headers.common[‘If-Match’] = $scope.edit.tag;

Как только заголовки будут определены, мы сделаем запрос PATCH $ http.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
$http({
    method: ‘PATCH’,
    cache: false,
    url: ‘http://127.0.0.1:5000/item/’ + $scope.edit.id,
    data: {
        name: $scope.edit.task
    }
}).
success(function(data, status, headers, config) {
    $(‘#editModal’).modal(‘hide’);
    getAllTask();
}).
error(function(data, status, headers, config) {
    console.log(data, status);
});

Как видно из приведенного выше кода, при успешном обновлении мы закрыли режим редактирования и перезагрузили все задачи, связанные с конкретным пользователем.

Сохраните все изменения и перезапустите сервер. Укажите в браузере http: // localhost: 3000 и войдите в систему, используя действительные учетные данные. После входа попробуйте отредактировать конкретную задачу, нажав кнопку редактирования.

Перед удалением задачи нам нужно показать всплывающее окно подтверждения. Итак, в userHome.html добавьте следующий HTML-код для всплывающего окна подтверждения удаления.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<div class=»modal fade» id=»deleteModal» tabindex=»-1″ role=»dialog» aria-labelledby=»deleteModalLabel» aria-hidden=»true»>
    <div class=»modal-dialog»>
        <div class=»modal-content»>
            <div class=»modal-header» style=»text-align:center;»>
                <h4 class=»modal-title» style=»color:red;»
            </div>
  
            <div class=»modal-footer»>
                <button type=»button» class=»btn btn-default» data-dismiss=»modal»>Cancel</button>
                <button type=»button» class=»btn btn-primary» ng-click=»deleteTask()»>Delete</button>
            </div>
        </div>
    </div>
</div>

Далее нам нужно определить функцию под названием confirmDelete которую мы уже прикрепили к кнопке Delete, используя директиву ngClick . Внутри функции confirmDelete мы сохраним идентификатор задачи и TAG, которые потребуются при вызове Delete API. Вот функция confirmDelete :

1
2
3
4
5
6
7
$scope.deletion = {};
 
$scope.confirmDelete = function(id, tag) {
    $scope.deletion.id = id;
    $scope.deletion.tag = tag;
    $(‘#deleteModal’).modal(‘show’);
}

Сохраните изменения и перезапустите сервер. Войдите в приложение и, находясь на домашней странице пользователя, нажмите кнопку Удалить , и вы сможете увидеть всплывающее окно подтверждения удаления.

Удалить всплывающее окно подтверждения

Далее мы определим еще одну функцию для удаления задачи. Мы уже прикрепили функцию deleteTask к кнопке Delete с ngClick директивы ngClick . Теперь давайте определим функцию userHome.js внутри userHome.js .

Подобно функции обновления, вызов запроса на удаление в Eve API требует, чтобы TAG ID был установлен в заголовке. Итак, сначала установите требуемые заголовки, как показано:

1
2
3
4
5
6
$http.defaults.headers.common = {«Access-Control-Request-Headers»: «accept, origin, authorization»};
$http.defaults.headers.common = {«Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»};
$http.defaults.headers.common[«Cache-Control»] = «no-cache»;
$http.defaults.headers.common.Pragma = «no-cache»;
$http.defaults.headers.common[‘Authorization’] = ‘Basic ‘+auth;
$http.defaults.headers.common[‘If-Match’] = $scope.deletion.tag;

Далее мы сделаем запрос DELETE для API REST http://127.0.0.1:5000/item/(itemId) .

01
02
03
04
05
06
07
08
09
10
11
12
$http({
    method: ‘DELETE’,
    cache: false,
    url: ‘http://127.0.0.1:5000/item/’ + $scope.deletion.id
}).
success(function(data, status, headers, config) {
    $(‘#deleteModal’).modal(‘hide’);
    getAllTask();
}).
error(function(data, status, headers, config) {
    console.log(data, status);
});

Как видно из приведенного выше кода, при успешном getAllTask вызове запроса DELETE мы скрываем модальное всплывающее окно подтверждения удаления и перезагружаем записи задачи, вызывая метод getAllTask . Вот полная функция deleteTask :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$scope.deleteTask = function() {
    $http.defaults.headers.common = {
        «Access-Control-Request-Headers»: «accept, origin, authorization»
    };
    $http.defaults.headers.common = {
        «Access-Control-Expose-Headers»: «Origin, X-Requested-With, Content-Type, Accept»
    };
    $http.defaults.headers.common[«Cache-Control»] = «no-cache»;
    $http.defaults.headers.common.Pragma = «no-cache»;
    $http.defaults.headers.common[‘Authorization’] = ‘Basic ‘ + auth;
    $http.defaults.headers.common[‘If-Match’] = $scope.deletion.tag;
 
    $http({
        method: ‘DELETE’,
        cache: false,
        url: ‘http://127.0.0.1:5000/item/’ + $scope.deletion.id
    }).
    success(function(data, status, headers, config) {
        $(‘#deleteModal’).modal(‘hide’);
        getAllTask();
    }).
    error(function(data, status, headers, config) {
        console.log(data, status);
    });
}

Сохраните вышеуказанные изменения и перезагрузите сервер. Укажите в браузере http: // localhost: 3000 и войдите в систему. На домашней странице пользователя нажмите кнопку « Удалить» , чтобы удалить несколько задач, и она должна заработать.

В этой части серии мы увидели, как использовать API-интерфейсы REST Python Eve, созданные в первой части серии, в приложении AngularJS. Мы реализовали несколько простых операций CRUD из нашего приложения AngularJS, используя Eve REST API. Я надеюсь, что этот урок послужит основой для создания чего-то удивительного.

Не стесняйтесь оставлять свои комментарии, исправления или вопросы ниже. Если вы нашли этот учебник полезным, посетите мою страницу инструктора для других учебников.

Исходный код из этого урока доступен на GitHub .