Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Angular Shopping Cart Editor

0.00/5 (No votes)
1 Mar 2016 1  
Angular Editor for the Angular Shopping Cart I posted here on CodeProject

Click here to see a working demo of this AngularJS Shopping Cart

Introduction

This is an Angular Shopping Cart Editor for the Angular Shopping Cart I published on CodeProject.

You can always find the latest version of my Angular Shopping Cart and editor on my website at:
www.Software-rus.com.

I wanted to create a simple editor in Angular for my Shopping Cart that would allow users to do CRUD operations on either a JSON file, or a local or remote database. My first instinct was to use a datagrid to display the products where users would select the product to edit by selecting a row in the datagrid but it soon became apparent that a datagrid would take up too much of the screen so I decided to use a different GUI layout by placing the GUI component for selecting the product to edit on the left side of the screen in a sidebar using a simple list leaving the larger area of screen for laying out the properties of each product as shown below. I like this layout and approach for an editor better than a datagrid. This layout and approach can be applied to editing any json file or database. The fields for each record are displayed in the main view called editor-details.htm. As you select an item in the sidebar, the main view updates to display that record for the selected item.

Data Sources

The user can easily modify how this editor loads and saves data from different data sources. The approach I used was to allow the user to set the default data sources in the config file and then select the data source to load the data from the dropdown menu shown below.

I used a DataService that loads data asynchronously that uses promise and deferred. A promise in Angular acts as an placeholder from where a JavaScript object returns some result as data which is done in an asynchronous way and it does not guarantee any fixed response time. This deferred object is constructed using $q.defer() to notify the success or unsuccessful completion of the asynchronous work, After completing the task in the deferred object, we can have access to the result in promise object. The Angular code for loading data in this way is very straightforward as shown below:

// I created a data service that provides the store and a shopping cart that 
// will be shared by all views (instead of creating fresh ones for each view). 

storeApp.factory('DataService', function ($http, $q, CONFIG) { 

// Can be loadded from a JSON file, a local .mdf database, or a remote database 
//'CF_DATA_FILE': 'ac_products/products.js', 
//'CF_DATA_LOCAL': '/crud.ashx?ac=getproducts&cn=local', 
//'CF_DATA_REMOTE': '/crud.ashx?ac=getproducts&cn=remote',

var dataIndex = localStorage["data_src_index"]; 
if (dataIndex == null || dataIndex == "undefined") { 
    dataIndex = 0; localStorage["data_src_index"] = 0; 
} 
var dataSource = CONFIG.CF_DATA_FILE; 
if (dataIndex == 0) { 
    // We randomize the string to prevent caching
    dataSource = "/" + CONFIG.CF_DATA_FILE + "?rnd=" + new Date().getTime(); 
} 
else if (dataIndex == 1) { 
    dataSource = CONFIG.CF_DATA_LOCAL; 
} 
else if (dataIndex == 2) { 
    dataSource = CONFIG.CF_DATA_REMOTE; 
} 
function Store() { 
    var productsDeferred = $q.defer(); 
    this.products = productsDeferred.promise; //this.products is a promise 
    $http.get(dataSource).success(function (data, status, headers, config) { 
    var products = []; 
    for (var i = 0, len = data.length; i < len; i++) { 
        var prod = data[i]; 
        if (prod.storeid == "7cc6cb94-0938-4675-b84e-6b97ada53978") { 
            var _expecteddate = new Date(prod.expecteddate); 
            prod.expecteddate = _expecteddate; products.push(prod); 
        } 
    } 
    productsDeferred.resolve(products); 
}).error(function (data, status, headers, config) { 
    alert("Please check you have updated ConnectionString with YOUR OWN information!"); 
    // Please update "remoteCartConnectionString" with your own data !!! 
});
...etc.

Note that I decided to load the Date field from the json file as a "Date" object as shown below:

var _expecteddate = new Date(prod.expecteddate);
prod.expecteddate = _expecteddate;

The Bootstrap 3 Menu and Navbar

The Bootstrap 3 menu used in this editor is discussed in detail in my shopping cart article referenced above so I won't repeat my discussion of all of the code in it here. You can upgrade to a higher version of Bootstrap for the Navbar and the necessary changes in the Navbar code for the dropdowns to work in the versions higher than Bootstrap 3 without using ui-bootstrap is shown below:

<li class="dropdown" ng-class="{open1: open1}">
    <a ng-click="navCollapsed = !navCollapsed" href="" class="dropdown-toggle" 

    data-toggle="dropdown" role="button" aria-expanded="false">
    <span class="fa fa-cart-plus"></span>&nbsp;Shopping Carts
    <span class="caret"></span></a>
    <ul role="menu" class="dropdown-menu">
        <li><a ng-click="open1=!open1" ng-href="some url" target="_blank">
            <img src="admin_img/codeproject.png" description="''" />
            &nbsp;Shopping Cart Article & Source Code</a></li>
    </ul>
</li>

HTML Fields

Several fields, namely, shortdesc, description, carousel_caption, and productname, in the shopping can have HTML formatting so I decided to add a very simple editor to these fields called nng-wig. You can get this module at http://ngmodules.org/modules/ngWig.

It is important that these fields do NOT contain any paragraph tags or complex HTML that would distort the look of the shopping cart so I limited the editing to bold, italic and <br /> for line breaks. I looked at a number of modules for editing the HTML content but the other editors insert too much unnecessary HTML in formatting that would distort the display in the shopping cart.

Embedded Video Tubes

I have always believed that a picture is worth a thousand words but a video is worth a million words so in my Angular Shopping Cart, I included the ability to insert either a picture or a video for the items in the store. It should be noted that there are a lot of video tube services today from Vimeo to the huge YouKu Tube Server in China that is now the world's largest television network.

sstoreApp.directive('embedVideo', function ($sce) { 
    return {
    restrict: 'EA', 
    scope: { tube: '=', code: '=' },
    replace: true,
    template: '<div class="video"><iframe src="{{url}}" frameborder="0" 
              webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></div>
    link: function (scope) {
    scope.url = "about:blank";
    scope.$watch('code', function (videoidVal) {
    if (videoidVal) {
        if (scope.tube === 'youtube') {
            scope.url = $sce.trustAsResourceUrl("http://www.youtube.com/embed/" + videoidVal);
        } else if (scope.tube === 'youku') {
            scope.url = $sce.trustAsResourceUrl("http://player.youku.com/embed/" + videoidVal);
        } else if ..... etc. // other tubes
        }
        scope.$apply();
    } }); } }; });

In some cases, the tube services provide a way to extract the image of a video's screen as in the case of YouTube videos. I added a link that appears to the left of the screen which the YouTube tube is selected and will show a link to the image of the screen of the YouTube video as shown below:

<a ng-show="product.showvideo && product.tube == 'youtube'" target="_self"

   href="https://img.youtube.com/vi/{{product.videoid}}/hqdefault.jpg"

   download="">YouTube Image</a> 

File Upload

The user can upload an image to the server in the editor. I placed all of the uploaded images in the ac_products directory but the user can create sub directories in this folder to help organize the images. By entering the name of the desired sub directory in the field to the right of the "img Dir" button and then pressing that button to set the path to include the sub directory they entered. For example, I am a collector of Golden Age Comic Books and I created a sub directory called "comics" for images of my comics. The Angular code for this is shown below:

$scope.uploadFile = function (event) 
{
    var fd = new FormData();
    for (var i in $scope.files) { 
        fd.append("uploadedFile", $scope.files[i]); 
    } 
    var imgDir = localStorage["img_dir"]; 
    var uploadUrl = "ImageHandler.ashx?dir=" + imgDir; 
    $.ajax({ url: uploadUrl, dataType: 'text', cache: false, 
        contentType: false, 
        processData: false, 
        data: fd, 
        type: 'post', 
        success: uploadComplete 
    }).error(function () { alert("failed!") }); 
}

Conclusion

The explanation of most of the code in this editor is explained in my article for the Angular Shopping Cart so I haven't repeated here. But I felt that this editor should be posted in its own article to keep things easier to follow. I also updated many features in my article for the Angular Shopping Cart I wrote and published here on CodeProject.

You can easily add my AngularJS Super Slick Carousel by just dropping in the code for my Angular Carousel. To add a carousel, go to:
http://www.codeproject.com/Articles/895739/Super-Slick-Carousel-Using-AngularJS-Directive

In the next few weeks, I will be updating this editor and my Angular Shopping Cart and posting an Angular 2 version of both my Shopping Cart and this editor with many new features.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here