Skip to content

Instantly share code, notes, and snippets.

@shidhincr
Forked from odino/desc.md
Created February 23, 2014 19:19
Show Gist options
  • Save shidhincr/9175885 to your computer and use it in GitHub Desktop.
Save shidhincr/9175885 to your computer and use it in GitHub Desktop.

Coding challenge: cartified!

Hey JavaScript talents, here at namshi.com, we are looking for you! Submit this coding challenge to alex.nadalin@namshi.com and we'll get back to you as soon as possible!

Your task is to implement a basic shopping cart for a website, following these basic rules:

  • the cart needs to be implemented as an AngularJS service
  • the cart should be retrieved from the localStorage, where it's stored under the key cart
  • every time an action is performed on the cart, it should be persisted on the localStorage
  • the cart should only know about item IDs and their quantity
  • you will write the cart by implementing the methods of the provided cart service in the template.js file contained in this gist: please fork it and submit your implementation
  • it should take you less than 1 hour to come up with an implementation, but we won't put any time limit for this challenge

Methods explanation

For some of the methods mentioned in the empty Cart service, we thought of giving you some explanation to better understand what they're there for.

Save

Checks if the cart can be persisted through the Reviewer service: if so, it persists it.

Clear

Empties the cart

Persist

Persist the cart on the localStorage

changeQuantity

Changes the quantity of one of the items in the cart.

Refresh

Notifies the application that the cart has been persisted, so that other parts of the app can modify themselves based on the latest cart update.

Dependencies

You are not allowed to inject any dependency on the Cart service other than the ones provided:

  • $rootScope: you might want to use it for whatever reason (for example, triggering events)
  • Reviewer: it's an angular service that will review the contents of the cart (Reviewer.review(cart), returns a promise)

What are we going to look for?

  • the fewer lines of code, the better
  • clear, coincise, DRY implementation
  • appropriate naming conventions

Another thing to consider: the cart should be working even when the user has multiple browser tabs open and is adding products from each of them.

We are not going to check the submitted script for syntax errors: concentrate on the design of the Cart service, we don't need to check for the small things

angular.module('services.cart', [])
.service('Cart', ['$rootScope', 'Reviewer', function ($rootScope, Reviewer) {
var getCart = function(){};
var addItem = function(){};
var addItems = function() {};
var save = function() {};
var remove = function () {};
var clear = function() {};
var persist = function() {};
var changeQuantity = function (){};
var refresh = function() {};
}]);
@shidhincr
Copy link
Author

Here is the answer to the question:

angular.module('services.cart', [])
    .service('Cart', ['$rootScope', 'Reviewer','$window' function ($rootScope, Reviewer, $window) { 

        'use strict';

        // Reading from local storage each time is costly. So keeping a private 'cart' variable.
        var cart, self = this;

        this.getCart = function(){
            var cartStr =  ( $window.localStorage && $window.localStorage.getItem('cart') ) || '{}';
            cart = JSON.parse( cartStr );
            return cart;
        };

        this.addItem = function( item ){
            cart = cart || this.getCart();
            cart[ item.itemId ] = item.quantity;
            this.save( cart );
            return this;
        };

        this.addItems = function( items ) {
            var self = this;
            angular.forEach( items, function(value, key){
                self.addItem( value );
            });
            return this;
        };

        this.save = function( cart ) {
            var self = this;
            Reviewer.review( cart ).then(function( result ){
                if( result=== true ){
                    self.persist( cart );
                }
            });
            return this;
        };

        this.remove = function ( itemid ) {
            cart = cart || this.getCart();
            if( cart[ itemid ] ){
                delete cart[ itemid ];
                this.save( cart );
            } 
            return this;
        };

        this.clear = function() {
            if( $window.localStorage && $window.localStorage.getItem('cart') ){
                $window.localStorage.removeItem('cart');
                this.refresh();
            }
            return this;
        };

        this.persist = function( cart ) {
            if( $window.localStorage ){
                $window.localStorage.setItem('cart', JSON.stringify( cart ) );
                this.refresh();
             }
            return this;
        };

        this.changeQuantity = function (itemid, newQuantity){
            cart = cart || this.getCart();
            cart[ itemid ] = newQuantity;
            this.save( cart );
            return this;
        };

        this.refresh = function() {
            $rootScope.$apply();
        };

        // real time cart updates between multiple tabs.
        angular.element( $window ).on( 'storage' ,function(event){
            if( event.key === 'cart' ){
                self.refresh();
            }
        });
    }]);

@shidhincr
Copy link
Author

Fixing a small issue with persist method

@shidhincr
Copy link
Author

Initially I missed the muliple tabs problem. updated the code to watch for changes in car for multiple tabs

@mayank12-3
Copy link

other files for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment