Using AngularJS $apply to call functions across different controllers within same module

Intro.

If you read my old post about Splitting Application Page into Separate AngularJS MINI Components , you might need to also read this post as i am talking here about a way to call a controller function from different $scope using the $apply module (Digest Loading).

Why we might need this?

This is important when we are inside a $scope of controller of a directive or what ever and we need to call or execute another controller $scope function to get or post or what ever the function does.

Indeed you can use the AngularJS $rootscope but all am doing here is introducing another solution.

How to do it ?

Lets assume that we have two different Controllers assigned to two different Directives and two different modules, and from the first Controller ($scope) we need to call function inside second Controller ($scope).

In real case, this could be a “Menu Controller Btn.” toggles “Body Controller Div” Visibility  or what ever you might need.

This is a way to access another $scope functionality without changing the $scope.

First, assuming that the external $scope that we need to call a function inside is assigned to HTML Div or whatever with Class or Id, we need this to get the element assigned $scope by element ID or Class Name.

Note that all the following code snippets should be inside the first controller not the one the function implemented inside.

var externalScope = angular.element($("#comp-body")).scope();

I assumed here that we have an HTML Element with Id = comp-body and this element Controller is the one we seek its functions.

Then lets call the function inside this scope as if we are inside it

externalScope.$apply(function () {
 externalScope.doSomething();
});

Note that, doSomething should be in externalScope ($scope) or implemented this way:

$scope.doSomething = function()
{
//What ever ...
};

Important Note

In some cases you might need to add the last code snippet inside

$timeout(function () {
//put the $apply code here ...
});

to make sure you are not conflicting with same $scope in progress process.

 

Thanks,

Advertisements

Splitting Application Page into Separate AngularJS MINI Components

Intro.

In glance, and over decades of building many Web Applications, i can say that we are the lucky generation who has the opportunity to witness the “Rapid Evolution” of the front end development. And am not here to utilize this post for talking about the historical road map or even to judge any of these many sprints, am only giving a modern “Technologically Oriented” technique to build a (Smarter, Easier to Maintain, Better for re usability) and Firm Web Application page using AngularJS 1.x.

Case Study

I need to build an application page(s) with several parts and to provide a smart stable way to communicate between these parts and indeed to reuse them in other pages.

Assumption

I will assume that you have enough experience with AngularJS and good understanding to the basic AngularJS Definitions like (Module, Directive, Service, Controller and Template). and Upon this assumption i just guide you to use these framework in way to provide the Titled “Split Your Application Page Into MINI Components”.

Step 1: Conceptually Split Your Page to as MINI Components as you can.

I remember that I’ve worked in application and i created a component for a “Button” and i handled the Hover, Click, In Progress behavior all inside this Directive.

This Step is very important but don’t spend a lot in as it is kind of recursive phase to keep updating and split more or merge according to how work goes.

I will give you a hint of some elementary concepts to take care while splitting the page into Components:

  1. Define the Globally Shared Parts (e.g. Header, Footer, Menu, …etc).
  2. Define the Partially Shared Parts (e.g. Profile Picture in account management Pages)
  3. Define or Draw the different page parts Dependency and Communication (In/Out) (e.g. A Btn. on the header can Toggle Page body contents visibility, or like Filter changes should update results).
  4. Avoid Over Splitting that will add useless effort to integrate and inject.

and overall, stop we you feel you are about to loose the Orchestration between all page parts.

Step 2: Build The Solution Structure 

There are several opinions regarding this part and different schools, and i can’t tell you whats better but you have to always know that whatever concept you will implement, you will sacrifice the strength of the other one. I will show here two different ways and indeed you can scout over another.

The Functional Structure people here separate the components by function, it means every component with separate functionality be in a separate folder contains all of its artifacts (e.g. JS, HTML, LESS or CSS), and also the sub components.

pic-1

Pic 1 : The Functional Structure

The File Type Structure This one is not business or functional oriented as mush as it is a development structure, where you are grouping the same File Type artifacts in the same Folder, and you use the file name to refer to the function related to.

pic-2

Pic 2:The File Type Structure

You are the best to define the need to pick any or merge between them to define your own structure, but you always should consider some elements to decide based upon, like

  1. How you will bundle the application , as the File Type is mush easier that the Functional one in terms of bundling .
  2. Minification Scripts.
  3. Template Mapping and Template Path Security configurations.

Step 3: Build the Globally Shared Components First then Page Specific Components.

Because 99% of the Globally Shared components are the most simple components and the less dependent on other parts, so you better start with to build and define your framework first and firmly continue injecting further components.

Sample Component Implementation (Building Header Component)

Define the Component module to use later in Parent Module injection.

angular.module('comp-header', [])

Assign the Component Directive pointing to the Component Template.

angular.module('comp-header', []).directive('compHeader', function () {
return {
        templateUrl: 'components/header/template.html' 
       };
});

Create the directive Controller

angular.module('fcomp-header').controller('CompHeader',
['$scope', '$element', '$timeout',
function ($scope, $element, $timeout,) {

angular.element(document).ready(function () {
    //Write Down The Directive Start Up Logic Here
});
}]);

Build The Component Template (HTML) and assign the created Controller to

< div class="comp-header" ng-controller="CompHeader">
Write Down Your HTML here ...
< /div>

Inject the Created component to the Page Module

angular.module('home-page', ['ngRoute', 'ui.bootstrap', 'ngAnimate', 'comp-header']);
angular.module('home-page');

Finally : Use the components in the home page

< div id="CompHeader">< /div>

Now, You should be able to move on with the rest of your components and keep injecting in the Page of interest.

Further to read in same context:
1. Using Angular $apply to call functions across different controllers within same module.
2. Using Angular $sceDelegateProvider to add the Directive Template URL to the Module White List.

Sharepoint 2010 Javascript Conflict with SVG Element Mouse Down event

I was working on a project with SVG element inside SharePoint 2010 Application Page, the Issue happened when i was trying to handle ‘onmousedown’ events for a DIV element containing this SVG.

SharePoint throw this Webpage JavaScript error:

Object doesn't support property or method 'split' ..

Here is the story … the issue come inside ScriptResource.axd only in IE9 and IE9 in the last line at this function.

Sys.UI.DomElement.containsCssClass = function Sys$UI$DomElement$containsCssClass(element, className) {
    ///summary locid="M:J#Sys.UI.DomElement.containsCssClass";
    /// param name="element" domElement="true";/param;
    /// param name="className" type="String";/param;
    /// returns type="Boolean";/returns;
  var e = Function._validateParams(arguments, 
  [{name: "element", domElement: true},
   {name: "className", type: String}]);
    if (e) throw e;
    return Array.contains(element.className.split(' '), className);
}

after tracking the Issue i found that the root cause comes from a call from inside SP.Ribbon.debug.js validation function. i won’t illustrate more about this as it didn’t help me any more to fix this issue. all i believe from this that SharePoint 2010 JavaScript APIs not yet well familiar with these HTML5 tags that doesn’t have a String Classname property where it it search on on Classname attribute and operate with this attribute as a string.

the point is that SVGElement is already has a Classname attribute, but it is not a string anymore, it is an Array or 2 items, animVal & baseVal and both are strings.

So, when the function tried to split an array of strings it throw error where there is no implementation for a Split function in the Array Prototype.

and here is the solution, actually it wasn’t a solution as an workaround but it works for me.

simply, if the browser tries to apply Split function on array, and no split function found, i implemented a Useless Split function for the Array Prototype returns empty Array. and that indeed won’t affect any of the functionality workflow and that what i am sure about.

in the Document.Ready and before any thing , i check on the browser mode and implemented he Split function. here is the code.

jQuery(document).ready(function () {
if (document.documentMode && document.documentMode = 9) 
{
SVGAnimatedString.prototype.split = function (value)
{ 
return new Array(); 
};
}
});

and that solved the issue.