Showing posts with label Framework. Show all posts
Showing posts with label Framework. Show all posts

Monday, June 23, 2014

How to Access $scope Variable Outside AngularJs Controller

Recently I was working with AngularJs and there was a requirement to call a AngularJs controller function forcefully from other events.  So for that we have to access $scope variable of a controller. This short blog is about accessing $scope variable.

In AngularJs all the scopes are bound to DOM so to access $scope first we have to get the HTML element. You can either use jQuery selectors to get elements or you can use standard document.getElementById method. For example.

var scope= angular.element($(".classselector")[0]).scope();

This gives you the scope of the the element. Once you have the scope you can call respective method of controller.  There is also other way to find out the scope if you don't have reference to element. You can find scope by name of controller.

var scope = angular.element($('[ng-controller=myController]')).scope();

After you make changes to variables of scope you have to call apply method so the AngularJs framework is notified about changes.

scope.$apply();

Hope this helps you.


Saturday, June 21, 2014

AngularJs Communicate Between Directives and Controllers

Hello,

Recently in one of my project we were using AngularJs and created a directive for timepicker where user can enter timer in hh:mm AM/PM format. Now on one of the HTML form we have a button. When the button is clicked we have to disable the input for the timepicker. For that we have to access scope of directive from scope of AngularJs controller so that se can disable the respective field. In this blog I am going to explain how to do this.

AngularJs allows you to create directives with isolated scope which has some binding to parent scope. Bindings are defined by specifying attributes in HTML.  In some cases it may not be good as it's hard to synchronize both the scopes. So ideally parent and directive scope should be maintained separately. Better way to communicate between directives and controllers is through directive attributes. Let's see and example.  I have defined my HTML as follow for my timepicker directive.

<timepicker is-not-open="notOpen" hour-step="1" minute-step="30" show-meridian="true"></timepicker>

As you can see above is-not-open is the attribute defined for directive and it is bind to notOpen variable in my controller.

$scope.notOpen = false;

Now lets see how to mention attribute in directive scope.

angular.module('ui.bootstrap.timepicker', [])
.directive('timepicker', ['timepickerConfig', function (timepickerConfig) {
  return {
    restrict: 'EA',
    require:'?^ngModel',
    replace: true,
    scope: { isNotOpen: "=" },
    templateUrl: 'template/timepicker/timepicker.html',
    link: function(scope, element, attrs, ngModel) {
     
    }
  };
}]);

As you can see in above code we have defined attribute with scope: { isNotOpen: "=" }. Now you can define a function to watch this variable in directives. For example there is a method in parent controller which sets notOpen variable to true.

$scope.setNotOpenStatus = function(){
      $scope.notOpen = true;
}

Once it is set here, the directive is notified about the change and as I mentioned you can keep watch on the attribute.

scope.$watch('isNotOpen', function (newValue, oldValue) {
          if(newValue == true){
              //do something
          }
});

Same way you can have watch function in parent controller which would be notified if attribute value is changed inside directive.

Hope this helps you.

Wednesday, May 28, 2014

AngularJs and $scope.$apply - When and How to use $apply for AngularJs scope

In this blog I will explain when to use $apply for AngularJs $scope and how to use it. You may have encountered the situation where you update the variables bind to AngularJs view but it does not update views. So here I will explain why it happens and how to resolve it. Also you need to know how to use $apply carefully else it may give you error that $apply is already in progress.

First lets understand how the AngularJs data binding works.AngularJs framework monitors data changes with the digest cycles. That means it checks it frequently in digest cycle then framework will be notified if you have made any changes in managed code. But there are chances that you have some external events like Ajax callbacks or some native click events. These event runs outside the scope of AngularJs digest cycles. So the framework does not know about any changes made during this events. You have to tell the framework that there are changes. Here $apply comes to the picture. It lets you start digest cycle explicitly. So that your frameworks knows that there are changes. Lets assume that you have variable $scope.myVar and you changed its value in native click event. So you need to tell Framework that it is changed. So if you simply use,

$scope.myVar = 'New Value';

It will not work. Instead of this you have to use

$scope.$apply(function(){
      $scope.myVar = 'New Value';
});

or you can use this syntax.

$scope.myVar = 'New Value';
$scope.$apply();


This shall notify the framework that the value is changed. It's not always safe to use $apply as I mentioned earlier. If the digest cycle is already in progress and you try to set it and with $apply it will give you an error. So if you have condition like your variable is updated at common function which you calls from AngularJs managed code and outside events. you have to first check it digest cycle is already in progress. If not then only use $apply. You can check it with following code.

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
       $scope.myVar = 'New Value';
       $scope.$apply();
}

This will be the safe apply and it will not give you any error .


Wednesday, December 25, 2013

Adjust Sencha Touch Carousel Indicators

Hello,

Recently we have a requirement in one of our project, to move carousel indicators outside the carousels. See the image below.

Now the issue was, main div container for the indicators is using the inline styling to position indicators based on user preferences. So we can override with class as we have to change the logic of the inline style. For that you have to override base class of Sencha Touch, name of the class is Ext.carousel.Indicator, you will find this class in src/carousel/indicator.js file in your sencha touch source code. Find the following function in the class.

updateDirection: function(newDirection, oldDirection) {
        var baseCls = this.getBaseCls();

        this.element.replaceCls(oldDirection, newDirection, baseCls);

        if (newDirection === 'horizontal') {
            this.setBottom(0);
            this.setRight(null);
        }
        else {
            this.setRight(0);
            this.setBottom(null);
        }
    }

Here you can see it's setting bottom property to zero. We have to override this function. Create an override.js file and attach it to your index.html file after sencha touch js file and add following code to it.

Ext.override(Ext.carousel.Indicator, {
    updateDirection: function(newDirection, oldDirection) {
        var baseCls = this.getBaseCls();

        this.element.replaceCls(oldDirection, newDirection, baseCls);

        if (newDirection === 'horizontal') {
            this.setBottom(-20);
            this.setRight(null);
        }
        else {
            this.setRight(0);
            this.setBottom(null);
        }
    }
});

As you see in the above code, we set bottom property to -20. You can use your own number here depending on your designs.

Hope this helps you.