В предыдущей части этого урока мы увидели, как начать создавать простую корзину с помощью AngularJS. Мы создали простой дизайн, но на самом деле не было достаточно AngularJS, чтобы назвать его AngularJS-приложением. В этой части серии руководств мы создадим пользовательскую директиву AngularJS для реализации необходимой функциональности.
Начиная
Давайте начнем с клонирования исходного кода предыдущего урока из GitHub .
1
|
git clone https://github.com/jay3dec/AngularShoppingCart_Part1.git
|
После клонирования исходного кода перейдите в каталог проекта и установите необходимые зависимости.
1
2
|
cd AngularShoppingCart_Part1
npm install
|
Как только зависимости установлены, запустите сервер.
1
|
node server.js
|
Укажите в браузере http: // localhost: 3000 /, и приложение должно быть запущено.
Создание директивы контрольного списка
На странице cart.html
элементы и их параметры повторяются. Поэтому для этой цели мы создадим директиву AngularJS, которая будет создавать элементы и их параметры в соответствии с данными в серверной части. Для простоты рассмотрим следующие элементы в корзине:
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
[{
‘item’: ‘Hard Disk’,
‘id’: ‘HD’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘200GB’,
‘price’: ‘2000’
}, {
‘size’: ‘400GB’,
‘price’: ‘4000’
}]
}, {
‘item’: ‘CPU’,
‘id’: ‘CPU’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘i3’,
‘price’: ‘20000’
}, {
‘size’: ‘i5’,
‘price’: ‘25000’
}]
}, {
‘item’: ‘Monitor’,
‘id’: ‘MON’,
‘selected’: 0,
‘prices’: [{
‘size’: ’16\»,
‘price’: ‘3000’
}, {
‘size’: ’19\»,
‘price’: ‘5000’
}]
}, {
‘item’: ‘Optical Mouse’,
‘id’: ‘MOU’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘Optical’,
‘price’: ‘350’
}, {
‘size’: ‘Advanced’,
‘price’: ‘550’
}]
}, {
‘item’: ‘RAM’,
‘id’: ‘RM’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘4GB’,
‘price’: ‘4000’
}, {
‘size’: ‘8GB’,
‘price’: ‘8000’
}]
}, {
‘item’: ‘USB Keyboard’,
‘id’: ‘KEY’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘Standard’,
‘price’: ‘2500’
}, {
‘size’: ‘Advanced’,
‘price’: ‘4500’
}]
}]
|
Добавьте следующие данные внутри CartCtrl
.
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
$scope.shopData = [{
‘item’: ‘Hard Disk’,
‘id’: ‘HD’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘200GB’,
‘price’: ‘2000’
}, {
‘size’: ‘400GB’,
‘price’: ‘4000’
}]
}, {
‘item’: ‘CPU’,
‘id’: ‘CPU’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘i3’,
‘price’: ‘20000’
}, {
‘size’: ‘i5’,
‘price’: ‘25000’
}]
}, {
‘item’: ‘Monitor’,
‘id’: ‘MON’,
‘selected’: 0,
‘prices’: [{
‘size’: ’16\»,
‘price’: ‘3000’
}, {
‘size’: ’19\»,
‘price’: ‘5000’
}]
}, {
‘item’: ‘Optical Mouse’,
‘id’: ‘MOU’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘Optical’,
‘price’: ‘350’
}, {
‘size’: ‘Advanced’,
‘price’: ‘550’
}]
}, {
‘item’: ‘RAM’,
‘id’: ‘RM’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘4GB’,
‘price’: ‘4000’
}, {
‘size’: ‘8GB’,
‘price’: ‘8000’
}]
}, {
‘item’: ‘USB Keyboard’,
‘id’: ‘KEY’,
‘selected’: 0,
‘prices’: [{
‘size’: ‘Standard’,
‘price’: ‘2500’
}, {
‘size’: ‘Advanced’,
‘price’: ‘4500’
}]
}];
|
Удалите повторяющийся HTML-код cart.html
из cart.html
. Мы создадим HTML динамически, используя ngRepeat и $scope.shopData
. Добавьте следующий HTML-код в первый столбец .row
div.
1
2
3
4
5
6
7
8
|
<div class=»col-xs-7 col-md-8 col-sm-8 col-lg-8″>
<div class=»panel panel-primary» ng-repeat=»q in shopData»>
<div class=»panel-heading»>
<h3 class=»panel-title»>{{q.item}}</h3>
</div>
</div>
</div>
|
Как видно из приведенного выше кода, используя ngRepeat
мы итерировали по shopData
и визуализировали HTML. Сохраните вышеуказанные изменения и перезагрузите сервер. Обновите страницу, и вы сможете просматривать элементы, отображаемые на странице.
Далее мы покажем опцию, доступную вместе с конкретным элементом, таким как его размер и цена (см. Данные JSON). Для этого мы создадим нашу собственную директиву AngularJS. Директивы AngularJS являются одной из самых мощных функций AngularJS. Для получения подробной информации о директивах AngularJS, обратитесь к официальным документам .
Давайте создадим пользовательскую директиву с именем checkList
. Откройте cart.js
и создайте новую директиву, как показано:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
.directive(‘checkList’, function() {
return {
restrict: ‘E’,
template: function(elem, attrs) {
return ‘<div class=»panel-body»>\
<div class=»radio»>\
<label><input type=»radio»>Option1</label>\
</div>\
<div class=»radio»>\
<label><input type=»radio»>Option2</label>\
</div>\
<div class=»radio»>\
<label><input type=»radio»>Option2</label>\
</div>\
</div>’
}
};
})
|
Эта директива имеет имя checkList
. Директива checkList
имеет два параметра: restrict
и template
. Restrict
определяет, как будет вызываться директива. Поскольку мы определили E, оно будет называться именем элемента, например:
1
|
<check-list></check-list>
|
Поле template
определило HTML-код, который заменит директиву checkList
на странице. Мы использовали тот же статический HTML-код, что и раньше. Теперь вызовите директиву checkList
на странице cart.html
.
1
2
3
4
5
6
|
<div class=»panel panel-primary» ng-repeat=»q in shopData»>
<div class=»panel-heading»>
<h3 class=»panel-title»>{{q.item}}</h3>
</div>
<check-list></check-list>
</div>
|
Сохраните вышеуказанные изменения и обновите страницу корзины. Вы должны иметь возможность просматривать статические параметры HTML на странице корзины.
Теперь давайте заставим директиву читать данные из $scope.shopData
. Во-первых, вместо повторения параметров внутри директивы, мы будем использовать ngRepeat для итерации параметров. Измените директиву checkList
как показано, чтобы сделать ее динамичной.
1
2
3
4
5
6
7
|
template: function(elem, attrs) {
return ‘<div class=»panel-body»>\
<div class=»radio» ng-repeat=»i in option»>\
<label><input type=»radio»>{{i.size}} Rs.{{i.price}}</label>\
</div>\
</div>’
}
|
Как видно из приведенного выше кода, мы ожидаем, что option
будет передана в директиву. Таким образом, из части HTML мы должны определить атрибут для директивы checkList
именем option
и передать необходимые данные. Добавьте option
в cart.html
как показано:
1
2
3
4
5
6
|
<div class=»panel panel-primary» ng-repeat=»q in shopData»>
<div class=»panel-heading»>
<h3 class=»panel-title»>{{q.item}}</h3>
</div>
<check-list option=»q.prices»></check-list>
</div>
|
Чтобы получить доступ к переданному option
внутри директивы, нам нужно определить область действия. Внутри директивы checkList
определите scope
как показано:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
.directive(‘checkList’, function() {
return {
restrict: ‘E’,
scope: {
option: ‘=’
},
template: function(elem, attrs) {
return ‘<div class=»panel-body»>\
<div class=»radio» ng-repeat=»i in option»>\
<label><input type=»radio»>{{i.size}} Rs.{{i.price}}</label>\
</div>\
</div>’
}
};
})
|
Таким образом, прайс-лист различных товаров из $scope.shopData
передается в директиву. Сохраните вышеуказанные изменения и перезагрузите сервер. Обновите страницу, и вы сможете увидеть размер и цену каждого элемента в качестве параметров на странице.
Теперь, если вы попытаетесь щелкнуть опцию переключателя для определенного элемента, оба будут выбраны. Чтобы гарантировать, что один элемент выбран одновременно, мы сгруппируем переключатели. Для этого нам потребуется передать еще один атрибут name
в директиву из представления HTML. Поэтому добавьте новый атрибут name
в check-list
из представления. Мы передадим ID
элемента в качестве name
, поскольку он уникален для каждого элемента.
1
|
<check-list name=»q.id» option=»q.prices»></check-list>
|
Теперь добавьте еще одну переменную в область действия директивы, чтобы сделать ее доступной в шаблоне директивы.
1
2
3
4
|
scope: {
option: ‘=’,
name: ‘=’
}
|
Внутри template
директивы HTML добавьте переданное имя в качестве имени переключателя, которое будет группировать переключатели определенных элементов.
1
|
<input type=»radio» name=»{{name}}»
|
Сохраните изменения и обновите страницу. Попробуйте выбрать переключатели для определенного элемента, и вы сможете выбрать только по одной за раз.
Расчет итога на основе выбранных опций
Основываясь на выбранных пользователем товарах, мы должны показать итоговую цену всех выбранных товаров. Для этого мы создадим функцию $scope
которая называется total
, которая будет суммировать итоговую цену. Каждый раз, когда пользователь выбирает элемент, мы обновляем переменную, выбранную в JSON $scope.shopData
. Затем этот JSON повторяется, чтобы получить общую стоимость выбранных товаров. Вот total
функция.
01
02
03
04
05
06
07
08
09
10
|
$scope.total = function() {
var t = 0;
for (var k in $scope.shopData) {
t += parseInt($scope.shopData[k].selected);
}
return t;
}
|
Прямо сейчас мы показываем жестко закодированное значение 100 рупий в общем DIV. Вместо этого мы просто вызовем функцию total.
1
|
<h2>Rs.
|
Сохраните изменения и обновите страницу. Если вы попытаетесь выбрать разные варианты, общая сумма на самом деле не изменится. Это потому, что начальное значение selected
переменной в JSON равно 0 и не обновляется при выделении. Итак, давайте передадим выбранное значение из JSON в директиву и обновим его, когда выбран переключатель. Измените представление HTML, чтобы включить еще один selected
атрибут в checkList
директивы checkList
.
1
|
<check-list name=»q.id» selected=»q.selected» option=»q.prices»></check-list>
|
Добавьте selected
в область действия директивы, чтобы получить доступ к ней внутри директивы.
1
2
3
4
5
|
scope: {
option: ‘=’,
name: ‘=’,
selected: ‘=selected’
}
|
Мы установим selected
в директиву ngModel
а i.price
в директиву ngValue
. Следовательно, всякий раз, когда выбран переключатель, его значение обновляется в selected
атрибуте JSON $scope.shopData
.
1
|
<input type=»radio» ng-model=»$parent.selected» ng-value=»{{i.price}}» name=»{{name}}»>
|
Сохраните вышеуказанные изменения и обновите страницу. Попробуйте выбрать опции переключателя, и в зависимости от выбора, Total
цена должна быть обновлена.
Вывод
В этой части серии руководств мы создали специальную директиву и использовали ее в нашем простом приложении для корзины покупок. В следующей части этой серии мы увидим, как сделать так, чтобы общий div всегда фиксировался сверху при прокрутке вниз. Также будет реализована страница оформления заказа, где будут отображаться выбранные товары и цены с кнопкой возврата на страницу корзины для настройки выбора.
Исходный код из этого урока доступен на GitHub . Дайте нам знать ваши мысли или любые исправления в комментариях ниже!