Monday, 6 June 2016

Creating a Star Control in HTML using Angular Js


In this article we are going to see how to create a Star Rating control in the HTML as Element or as Attribute using the Angular js. To do this we are going to take create the Directive in Angular js, First Let we see what kind of element or Attribute we are going to create and what kind of output it will give ?

Below Code Snippet is we trying to do





Output:




From the Code we can render a Star Control, using the some of the properties it will have some  behavior change.

custom-rating is the act as element or attribute for render a star control, it have few options
readonly : set true for this attribute if you want the star control as readonly
max : set the number of star you want to render
star-size : size of the star control
rating-value : specify the rating value of a control
on event is there to trigger for the change in the star value when user clicked, then use the 
on-rating-changed with a function passing parameter in the name of rating , which consists the value, now you can trigger the value to the server.

Now we start to build the directive.

Add the following jquery in the HTML.


    <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>

    <script type="text/javascript" src="js/angular.min.js"></script>

Then start writing coding in Angular.

Create a Module and controller

First step is create a module in separate js file and include in the HTML.

        var myApp = angular.module('myApp', []);

        myApp.controller('BlogController'function ($scope, $window) {
            $scope.sample = 'Blog Testing';

            $scope.rating = 5;
            $scope.rating2 = 1;

            $scope.saveRating = function (rating) {
                console.log('Rating selected ' + rating);
            };

            $scope.Sample = function (rating) {
                console.log('sample ' + rating);
            };

        });


Create a Directive

        myApp.directive('customRating'function () {
            return {
                restrict: 'AE',
                template: '<ul class="rating">' +
                         '<li ng-repeat="star in stars"  ng-class="star" ng-                                                click="toggle($index)">\u2605</li>' +
                         '</ul>',
                scope:
                {
                    ratingValue: '=',
                    max: '=',
                    readonly: '@',
                    starSize: '=',
                    onRatingChanged: '&'
                },
                link: function (scope, element, attrs) {

                   
                    var updateStars = function () {
                        scope.stars = [];
                        for (var i = 0; i < scope.max; i++) {
                            scope.stars.push({ filled: i < scope.ratingValue });
                        }
                    };

                    element.css('font-size', scope.starSize);

                   
                    scope.toggle = function (index) {
                        if (scope.readonly && scope.readonly === 'true') {
                            return;
                        }
                        scope.ratingValue = index + 1;

                        scope.onRatingChanged({ rating: index + 1 });
                    };

                   
                    scope.$watch('ratingValue'function (oldval, newval) {
                        if (newval) {
                            updateStars();
                        }
                    })

                }

            }
        });




So now when include the custom js in the Html, we can able to render the Star control .Now when ever user change the value in one star it affects others because of binding, at the same time we are trigger the changes to the server.



From this article you can learn how to render a star control tag in Html using Angular Js.




UI-Sortable directive not works for the drag while sorting between the elements on the first drag or first click using jquery 2.0.0 and Angular js - Resolved


In this article we are going to see a bug, which is present in the jquery,because of that it affects the Angular ui-sortable directive.now let we see about the sorting between the elements by dragging using angular js, To do this we need following references.


<script type="application/javascript" src="js/jquery-2.0.0.min.js"></script>
<script type="application/javascript" src="js/jquery-ui.min.js"></script>
<script type="application/javascript" src="js/bootstrap.min.js"></script>
<script type="application/javascript" src="js/angular.min.js"></script>
<script type="application/javascript" src="js/angular-ui.min.js"></script>

  
In this sample we take two different kind of sorting elements, one with static element, another with dynamic elements i.e adding elements at runtime using angular js

Code:

       <div style="float: left; margin: 20px">
            <h3>
                static element</h3>
            <ul ui-sortable="sortoptions" class="well" style="width: 400px">
                <li style="" class="well li">LG</li>
                <li style="" class="well li">Samsung</li>
                <li style="" class="well li">Videocon</li>
                <li style="" class="well li">Onida</li>
            </ul>
        </div>

        <div style="float: left; width: 400px; margin: 20px">
            <h3>
                dynamic element</h3>
            <ul id="sortid" ui-sortable="sortoptions" class="well">
                <li class="well alterli" ng-repeat="item in Items">{{item.name}}</li>
            </ul>
        </div>




Output:

Above dynamic element tag not able to drag and sort on first attempt, because of jquery 2.0.0



From the elements, both can be sort using dragging but there is a one issue with the second element, the second rendered elements can't able to drag on the first attempt, but it can drag and sort in second attempt, this issue only occurs in Jquery 2.0.0 when elements are rendered dynamically using ng-repeat. But it works correctly when using Jquery less than or above 2.0.0, This is working correctly for static declared elements Now we are going to see how to fix this issue, to drag the dynamically rendered elements in the first attempt for jquery 2.0.0 version


Why this issue occurs in dynamically rendered elements ?
           When adding the directive ui-sortable to the root tag, that particular element is rendered first,before the rendering of the child elements, because of this behavior drag is fails on the first attempt, it cant able to recognize the event. on the second attempt it success for the dynamic added elements.

How to fix this issue ?

For dynamic rendered elements,  adding a new directive along with ui-sortable directive, add the directive init-sort which i mention before , it will take care remaining things,now your elements are drag and sortable on the first attempt itself.

Directive: 
        samApp.directive('initSort'function ($compile) {
            return {
                restrict: 'A',
                scope: {
                    initSort: '='
                },
                transclude: false,
                link: function (scope, element, attrs) {
                    var firsttime = 0;
                    element.on('mouseover'function () {
                        if (firsttime == 0) {
                            element.sortable("refresh");
                            firsttime = 1;
                            console.log('Triggered');
                        }
                    });
                }
            };
        });



HTML
        <div style="float: left; width: 400px; margin: 20px">
            <h3>
                dynamic element</h3>
            <ul id="sortid" ui-sortable="sortoptions" init-sort class="well">
                <li class="well alterli" ng-repeat="item in Items">{{item.name}}</li>
            </ul>
        </div>



Output:



Full Code:
HTML 


<body ng-app="samApp">
    <div ng-controller="sampleController">

        <div style="float: left; margin: 20px">
            <h3>
                static element</h3>
            <ul ui-sortable="sortoptions" class="well" style="width: 400px">
                <li style="" class="well li">LG</li>
                <li style="" class="well li">Samsung</li>
                <li style="" class="well li">Videocon</li>
                <li style="" class="well li">Onida</li>
            </ul>
        </div>

        <div style="float: left; width: 400px; margin: 20px">
            <h3>
                dynamic element</h3>
            <ul id="sortid" ui-sortable="sortoptions" init-sort class="well">
                <li class="well alterli" ng-repeat="item in Items">{{item.name}}</li>
            </ul>
        </div>

    </div>
    <script type="application/javascript" src="js/jquery-2.0.0.min.js"></script>
    <script type="application/javascript" src="js/jquery-ui.min.js"></script>
    <script type="application/javascript" src="js/bootstrap.min.js"></script>
    <script type="application/javascript" src="js/angular.min.js"></script>
    <script type="application/javascript" src="js/angular-ui.min.js"></script>
    <script type="application/javascript" src="ang/samApp.js"></script>


</body>


Angular JS

        /**
        * Created by Rajesh on 20-08-2014.
        */

        var samApp = angular.module('samApp', ['ui']);

        samApp.controller('sampleController'function ($scope) {

        $scope.Items = [
                   { name: 'Rajesh' },
                   { name: 'Suresh' },
                   { name: 'Aneesh' },
                   { name: 'Gokul' }
             ];

            
        $scope.sortoptions = {
                update: function (event) {

                },
                stop: function (e, ui) {
                    console.log('stop item', ui.item.scope());
                    console.log('stop item', ui.item.sortable);
                    var item = ui.item.sortable.moved;
                    var fromIndex = ui.item.sortable.index;
                    var toIndex = ui.item.sortable.dropindex;
                    console.log(item, fromIndex, toIndex, $scope.dropTarget);
                },
                start: function (e, ui) {
                    console.log('start item', ui.item.scope());
                }
            };



        });

        samApp.directive('initSort'function ($compile) {
            return {
                restrict: 'A',
                scope: {
                    initSort: '='
                },
                transclude: false,
                link: function (scope, element, attrs) {
                    var firsttime = 0;
                    element.on('mouseover'function () {
                        if (firsttime == 0) {
                            element.sortable("refresh");
                            firsttime = 1;
                            console.log('Triggered');
                        }
                    });
                }
            };
        });




From this post you can see how to drag the elements in the first attempt when JQuery is 2.0.0.