One page shops with Magento & Angular Js - Vinai Kopp

Preview:

DESCRIPTION

This talk covers a special use case. On stores with a small number of products it can make sense to completely replace the usual Magento front end and build a single page shop. This page contains the product presentation and enables the customer to check out easily. No catalog browsing functionality is present, since the goal is to get the customer from product presentation to checkout as quickly and easily as possible. The front end communicates with Magento via the REST API to fetch product information, create the customers and processes the orders. Building the customer facing page with a framework like AngularJS makes the front end work fun and easy. On the backend, the Magento REST API needs to be extended in order to provide all required functionality. Moving more business logic to the client side enables the Magento store to scale with less resources. This talk will cover an overview over the architecture and the challenges to overcome when building a one page store.

Citation preview

Single PageShops

With MagentoAnd AngularJS

Who am I?Vinai

How did I get here?

Freelance again!

I want to write a book......about Magento

(one trick pony)

Iʹll Self Publish!...on Magento

Work, Lots!Fun StuffCodingMoney

Unfun StuffSettingsThemingEmail TemplatesTerms & ConditionsSupport

MORE FUN

WoW

MuchDifferent

So faster

News Learnin

VeryAngular

Such JS

So Modern

WoW

JavaScript MVC Toolkit

DI and Testability are at itsvery core

Clean separation of MVClayers

Many pre‑made Modules

No jQuery or Prototype!(okay, it has jQuery Light)

Web‑App

AngularJSFrontend

<= REST API => MagentoCustomersProductsOrdersPaymentsDownloads

Admin Interface

Planning

Reduce to the max!

Starting outMagento CE 1.8.1.0angular‑seed 

Magento REST APIBasics

REST API!==

SOAP APIs

Mage_Api2

Resources

Products,ProductCategories,ProductImages,ProductWebsites

Stock Items

Customers,CustomerAddresses

Orders,

Order Items,Order

Addresses,Order

Comments

Resource AttributesYou know the drill...

 Products have Names, ... Customers have Groups, ...

Resource Routes/api/rest/products/category/10/store/2

Route Action TypesCollection

/api/rest/products/category/10/store/2

Entity/api/rest/products/16

OperationsMapping of HTTP verbs

GET => retrievePOST => createPUT => updateDELETE => delete

Roles

Admin

Customer

Guest

What weʹve gotRoles Resources

Attributes

Routes

Action Types

OperatonTypes

That all?

ACL

Each role can be allowed or denied potential access to eachresource by operation type via api2.xml.

E.g. guests may retrieve products, but not create them.

Under System > Web Services > REST ‑ Roles each potential rolepermission has to be assigned, too.

Resource Attributes ACLSame as roles... defined in XML, but ACL also has to be

assigned in the DB through the backend.

System > Web Services > REST ‑ Attributes

Not so elegant transition from theory to real stuff =>

Customizethe REST API

Customer AuthenticationOAuth

Session Authentication!REST API requests always run in admin store scope.$_SERVER['MAGE_RUN_CODE'] is not evaluated.

Api2 Session Auth Adapter1.  If frontend cookie exists2.  Set current store to frontend3.  Start frontend session4.  Check if customer is logged in

Which store?1.  Evaluate store cookie2.  If not found, use the defaultwebsites default store view

3.  Hope the customer belongs tothe website

CodeVinaiKopp_Api2SessionAuthAdapter 

VinaiKopp_Api2SessionLogin 

More REST RelatedExtensions

VinaiKopp_Api2CreateAccountVinaiKopp_Api2DirectoryVinaiKopp_Api2SessionCustomerAddressVinaiKopp_Api2ForgotPasswordVinaiKopp_Api2DownloadsGrokking_Api2Checkout

(coming to github as time allows ‑ pls ask if you need sooner)

The Frontend

7thingsI digʹbout 

1. Modules

angular.module('magentoApp', []);

angular.module('magentoApp', ['ngRoute']);

Look Ma, Module Dependencies!

Modules provide things

angular.module('magentoApp', ['ngRoute']) .factory('Countries', function() { return { code: 'ES', name: 'Espania' }; });

Things modules provideServicesControllersDirectivesFilters

and more...

2. Dependency InjectionIf a module needs a thing...

...just add it to thearguments

.controller('RegistrationCtrl', function($scope, Countries) {

$scope.countries = Countries;

})

3. Mangling Protection

JavaScript CompressionI HAZ TEH MINIFICATSION! (meow)

Variable names made shorter...

KILLS the DI!

Mangling Protection

.controller('RegistrationCtrl', ['Countries', function($scope, Countries) {

$scope.countries = Countries;

}])

4. Promises

Asynchronous ThingsXHR Requests and setTimeout Callbacks

Callback Try & Catch

Countries.fetch(). then(verifyAddress). then(createAddress). catch(displayAlert);

Can be combined!

$q.all(Countries.fetch(), Regions.fetch()). then(verifyAddress). then(createAddress). catch(displayAlert);

5. REST Resources

Inject $resource...

.factory('ForgotPassword', ['$resource', function($resource) { return $resource('/api/rest/customer/forgotpassword/:email'); });

...and use var result = ForgotPassword.get({ email: email });

Custom actions!

.factory('ForgotPassword', ['$resource', function($resource) { var resource = $resource('/api/rest/customer/forgotpassword/:email', {}, { validate: {method: 'GET', isArray: true}, reset: {method: 'PUT', isArray: false} });});

Fluid code :) var result = ForgotPassword.verify({ email: email, token: token });

6. Model Data Binding

[   ]

<p>{{ example }}</p> <input type="text" ng-bind="example">

Show Example

7. Testability it('should call calcRowTotal() when addItem is called with a new item', function () { expect(cart.items.length).toBe(0); cart.addItem(mock_product); expect(mock_item.calcRowTotal).toHaveBeenCalled(); });

Would I do it again?

Yeaaah!

Complicationsaka ʺOpportunities for Growthʺ

Scope Nestingcan be tricky

Frontend ArchitectureBuild a mini‑framework

Session State ManagementSplash MessagesConsistent error handling

Bad Crunch‑TimeDescisions

Last Friday I was running out of time

so I decided to continue without TDD

A lesson learned...again

I need more time to test manually then to write the tests.

Dankeschön!

@VinaiKopp on 

Api2 Extensions on GitHub 

Recommended