frontend for the win
DESCRIPTION
TRANSCRIPT
FRONTEND FOR THE WIN!Антон Плешивцев, aviasales.ru
МЕТАПОИСК
МЕТАПОИСК
МЕТАПОИСК
МЕТАПОИСК
МЕТАПОИСК
LEGACY
• кастомное решение
• 10К строк кода без тестов
• виджет-ориентированная архитектура
ЖИДКОЕ ПРИЛОЖЕНИЕ
Поисковая формаПоиск
Выдача
Билеты
ФильтрыСостояние
Агенства
Фидбек
История
Календарь
INTERFACE
NEW AGE
• AngularJS
• 3K строк кода
• 80% покрытие тестами
СТРУКТУРА
СТРУКТУРАПоисковая форма
Билеты Фильтры
СТРУКТУРАПоисковая форма
Билеты Фильтры
Форма История поисков
Календарь
Отели
Билеты
Цена
Время
Вылет
…
ВЗАИМОДЕЙСТВИЕ ЧАСТЕЙ
ВЗАИМОДЕЙСТВИЕ
Билеты
Календарь
Отели
Билеты Фильтры
Цена
Время
Вылет
…
?
ВЗАИМОДЕЙСТВИЕ
Билеты
Календарь
Отели
Билеты Фильтры
Цена
Время
Вылет
…
service
ВЗАИМОДЕЙСТВИЕ
Билеты Фильтры
Календарь
Отели
Билеты
Цена
Время
Вылет
…
«Выдача с фильтрами»
МОДУЛИ
MODULE PATTERNvar testModule = (function () { ! var counter = 0; ! return { ! incrementCounter: function () { return counter++; }, ! resetCounter: function () { console.log( "counter value prior to reset: " + counter ); counter = 0; } }; !})();
AMD MODULE
//Calling define with a dependency array and a factory function define(['dep1', 'dep2'], function (dep1, dep2) { ! //Define the module value by returning a value. return function () {}; });
DEPENDENCY INJECTION
function MyController($scope, greeter) { ! $scope.test = true; ! $scope.check = function(){ greeter.check($scope.test); }; !}
Ядро
Ядро
Форма поиска Выдача
Ядро
Форма поиска Выдача
Форма История Билеты Фильтры
Ядро
Форма поиска Выдача
Форма История Билеты Фильтры
Поиск
Календарь Отели Выдача
Цена Время
Ядро
Форма поиска Выдача
Форма История Билеты Фильтры
Поиск
Календарь Отели Выдача
Цена Время
Ядро
Форма поиска Выдача
Форма История Билеты Фильтры
Поиск
Календарь Отели Выдача
Цена Время
у
Выдача
Билеты Фильтры
{ filters: {} tickets: [] }
{ tickets: [] filters: {} sort: function(){…} }
{ reset: function(){…} filters: {} tickets: [] }
Выдача Цена{ sorting: ‘price’ tickets: [] filters: {} sort: function(){…} }
{ visible: [1000, 10 000] reset: function(){} filters: {} tickets: [] }
Выдача
Билеты Фильтры
{ filters: {} tickets: [] }
{ tickets: [] filters: {} sort: function(){…} }
{ reset: function(){…} filters: {} tickets: [] }
Выдача Цена{ sorting: ‘price’ tickets: [] filters: {} sort: function(){…} }
{ visible: [1000, 10 000] reset: function(){} filters: {} tickets: [] }
Выдача
Билеты Фильтры
Выдача Цена$scope.filters.price = [1000, 15000]
Выдача
Билеты Фильтры
Выдача Цена
$scope.filters.price = [1000, 15000]
$scope.filters.price = [1000, 15000]
Выдача
Билеты Фильтры
Выдача Цена$scope.filters.price = [1000, 15000]
$scope.filters.price = [1000, 15000]
onchange(‘filters.price’, function(){ update_tickets(); })
PITFALL
PITFALLВыдача
Фильтры
Цена
$scope.filters = { price: [100, 10000], duration: [3600, 84600], … }
BEFOREВыдача
Фильтры
Цена $scope.filters
$scope.filters
$scope.filters
AFTERВыдача
Фильтры
Цена $scope.filters
$scope.filters
$scope.filters
TEMPLATES
UNOBTRUSIVENANO("templates.searches.tickets.widgets.proposals", function(NANO){ return NANO.templates(‘ticket.html’, { "@data-ticket-id": "ticket.id", "@data-source": "source", ".ticket_proposal": { "gate<-proposals": { ".gate_name": "gate.name", ".gate_select_button a@href": "gate.url", ".gate_select_button a@data-gate": "gate.id", ".gate_price": "gate.price", ".gate_payment_methods .payment_method": { "method<-gate.payment_methods": { "@class+": " #{method}" } } } } }); });
DECLARATIVE
<li class="proposal-carousel" ng-repeat="proposal in ticket.proposals_for_carousel()"> <a class="agency_offer" ng-click="buy_ticket(ticket, proposal)"></a> <span>{{ proposal.name() | cut:15 }}</span> <span class="price"> <span>{{ proposal.price() | current_price:search.currency }}</span> </span> </li>
UNOBTRUSIVElayout.find(".yes").bind("click", function(){ self.toggle(layout, "yes"); }); layout.find(".no").bind("click", function(){ self.toggle(layout, "no"); }); layout.find("#new_feedback").submit(function(){ return self._submit(); });
<form class="feedback"> <div class="yes">Да</div> <div class="no">Нет</div> ... </form>
+
DECLARATIVE<form class="feedback" ng-submit="submit()"> <div class="yes" ng-click='success(true)'>Да</div> <div class="no" ng-click='success(false)'>Нет</div> ... </form>
ИТОГИ
COMPOSITE ARCHITECTURE IS POWERFUL
PROTOTYPE INHERITANCE IS GOOD
DECLARATIVE ALWAYS BETTER THEN IMPERATIVE
ANGULARJS IS BETTER THAN ANYTHING ELSE
ABOUT
АНТОН ПЛЕШИВЦЕВ !twitter.com/allaud github.com/allaud https://www.facebook.com/ant.pl.3 !aviasales.ru