3

I must add I am working on Sharepoint 2013, visual web part. my ascx:

<%@ Control Language="C#" Inherits="SharePoint.BLL.UserControls.VODCatalog, SharePoint.BLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=81fc048468441ab3" %>
<%@ Register TagPrefix="SPWP" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"  Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>


<div ng-app="VODCatalogModule">
    <div class="wrapper" ng-view="">   
    </div>
</div>

My JS:

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

var testWPDefinedView = 'TopLevelView';

VODCatalogModule.config(function ($routeProvider) {
    $routeProvider.when('/TopLevelView', { controller: 'VODCatalogController', templateUrl: '/_catalogs/masterpage/html/VODCatalog_TopLevelView.html' })
                  .when('/LowLevelView', { controller: 'VODCatalogController', templateUrl: '/_catalogs/masterpage/html/VODCatalog_LowLevelView.html' })
                  .otherwise({ redirectTo: '/' + testWPDefinedView });
});

function VODCatalogController($scope, $http) {
    $scope.VODCatalogLevel = 1;
    $scope.BreadCrumbs = [];
    $scope.MainCatalog = [];
    $scope.NavCatalog = [];
    $scope.crumbsVisible = $scope.BreadCrumbs.length == 0 ? "hidden" : "";

    var getVODCatalogData = function (PARENT_VOD_CATALOG_GK, vodLevel) {
        var url = "VODCatalogHandler.ashx?action=GetVODCatalogData&vodLevel=" + vodLevel;
        if (PARENT_VOD_CATALOG_GK)
            url += "&PARENT_VOD_CATALOG_GK=" + PARENT_VOD_CATALOG_GK;
        $http.get(url, { cache: true })
            .success(function (data, status, headers, config) {
                setVODCatalogData(data, vodLevel);
            }).error(function (data, status, headers, config) {
                alert('ERROR in VODCatalogDataService get');
            });
    };

    var setVODCatalogData = function (data, vodLevel) {
        $scope.BreadCrumbs = data;
        $scope.MainCatalog = data;
        $scope.NavCatalog = data;
    };

    $scope.catalogItemClick = function (catalogItem) {
        getVODCatalogData(catalogItem.VOD_CATALOG_GK, ++$scope.VODCatalogLevel);
    };

    getVODCatalogData(null, $scope.VODCatalogLevel);
}

VODCatalogModule.controller("VODCatalogController", VODCatalogController);

My view (VODCatalog_TopLevelView.html):

<section class="zebra brightBGcolor">
    <div class="catalog">
        <div class="centerPage">
            <div class="pageTitle withBreadCrumbs">
                <h3>VOD</h3>
                <ul class="breadCrumbs {{ crumbsVisible }}">
                    <li>
                        <a href="#">VOD</a>
                    </li>
                    <li ng-repeat-start="crumb in BreadCrumbs">
                        <span>&nbsp;</span>
                    </li>
                    <li ng-repeat-end>
                        <a href="#">{{ crumb.NAME }}</a>
                    </li>
                </ul>
            </div>
            <ul class="list inRow4 clearfix">
                <li ng-repeat="catalogItem in MainCatalog" ng-click="catalogItemClick(catalogItem)">
                    <a class="box" href="#">
                        <img src="{{ catalogItem.MEDIA_URI_Complete}}" alt="">
                        <div class="textContainer">
                            <h4>{{ catalogItem.NAME }}</h4>
                        </div>
                    </a>
                </li>
            </ul>
        </div>
    </div>
</section>

At the start all looks great, it loads the 1st ajax call with all the pics and data.

Then when I click at one of the li's with the ng-click the 2nd ajax gets executed twice, once it gets the right data and immediately after it calls itself again with the initial call of getVODCatalogData(null, $scope.VODCatalogLevel); and brings back the old view.

When I tried to put something in module.run it also runs twice, can it help?

I would appreciate any hint and help as it is my 1st time with angular.

thx! ariel

EDIT: some more info - I put a log at the beginning of the controller and after the click the controller gets initialized again

2
  • Can you try to rename function VODCatalogController($scope, $http) { to function VODCatalog($scope, $http) { and VODCatalogModule.controller("VODCatalogController", VODCatalogController); to VODCatalogModule.controller("VODCatalogController", VODCatalog); Commented Aug 6, 2013 at 13:55
  • tried it, nothing changed... Commented Aug 6, 2013 at 14:17

2 Answers 2

12

If the controller is specified in the $routeProvider and in the HTML template it will get create once for each declaration.

Sign up to request clarification or add additional context in comments.

Comments

3

2nd Answer, the technical answer is that the $routeProvider caused it, i dont know why but when i change my "master" html to this:

<div ng-app="VODCatalogModule" ng-controller="VODViewsController" ng-switch on="templateUrl">
   <div class="wrapper" ng-switch-when="TopLevelView" ng-include="'/_catalogs/masterpage/html/VODCatalog_TopLevelView.html'" ng-controller="VODCatalogController"></div>
   <div class="wrapper" ng-switch-when="LowLevelView" ng-include="'/_catalogs/masterpage/html/VODCatalog_LowLevelView.html'" ng-controller="VODCatalogController"></div>
</div>

the controller finally was created only once. the conclusion is that if you gonna work with the $routeProvider then its only good for basic routing, anything more complex require work. the most famous article and example for that is Nested Views Routing-And Deep Linking With AngularJS who created a wonderful architecture, while my attempt that will be included in my blog is something more dynamic, i will try to read the params in the factory.

1st Answer: found the solution! i was not using MVC architecture. the controller is SUPPOSED to get recreated every time it is being called, and therefor trying to managed my data in the controller did a mess since the Ajax call has its promise promise return async then it recreates the controller.

the solution to that is to manage ONLY BEHAVIORS in your controller and all data in a service/factory/provider.

so here is the new JS:

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

    VODCatalogModule.factory('VODCatalogFactory', function($http) {
        var VODFactory = [];

        VODFactory.VODCatalogLevel = 1;
        VODFactory.PARENT_VOD_CATALOG_GK;

        VODFactory.getVODCatalogData = function (PARENT_VOD_CATALOG_GK) {
            var url = "VODCatalogHandler.ashx?action=GetVODCatalogData&vodLevel=" + VODFactory.VODCatalogLevel;
            if (PARENT_VOD_CATALOG_GK)
                url += "&PARENT_VOD_CATALOG_GK=" + PARENT_VOD_CATALOG_GK;
            return $http.get(url, { cache: true });
        };

        VODFactory.changeVODCatalog = function (level, PARENT_VOD_CATALOG_GK){
            VODFactory.VODCatalogLevel = level;
            VODFactory.PARENT_VOD_CATALOG_GK = PARENT_VOD_CATALOG_GK;
        };

        return VODFactory;
    });

    var testWPDefinedView = 'TopLevelView';
    //var testWPDefinedView = 'LowLevelView';

    VODCatalogModule.config(function ($routeProvider) {
        $routeProvider.when('/TopLevelView', { controller: 'VODCatalogController', templateUrl: '/_catalogs/masterpage/Yes/html/VODCatalog_TopLevelView.html' })
                      .when('/LowLevelView', { controller: 'VODCatalogController', templateUrl: '/_catalogs/masterpage/Yes/html/VODCatalog_LowLevelView.html' })
                      .otherwise({ redirectTo: '/' + testWPDefinedView });
    });

function VODCatalogController($scope, $http, VODCatalogFactory) {
    console.log("VODCatalogController ctor");
    $scope.crumbsVisible = !$scope.BreadCrumbs || $scope.BreadCrumbs.length == 0 ? "hidden" : "";

    $scope.catalogItemClick = function (catalogItem) {
        VODCatalogFactory.changeVODCatalog(++VODCatalogFactory.VODCatalogLevel, catalogItem.VOD_CATALOG_GK);
    };

    VODCatalogFactory.getVODCatalogData().then(function(response){
        $scope.BreadCrumbs = response.data;
        $scope.MainCatalog = response.data;
        $scope.NavCatalog = response.data;
    });

    VODCatalogModule.controller("VODCatalogController", VODCatalogController);

more in angularjs and ajax filtering refreshing

4 Comments

So I wanted to control some buttons on my arrow key. I added key event on window in my controller for the partial. It was getting added twice and getting called twice as well. this is not data that I am storing. this is behaviour right? so for now I keep a boolean in scope to check if I have already added the listener.
no, its an architecture problem by us developers not understanding MVC completely, i advice you to check the tutorial in my blog where i issue that exactly
I am facing the same issue, I added a service for my request, and still my controller is loading twice ! ( iam calling the controller only from my $stateProvider for the view)
why FROM the $stateProvider? you should only call it from a click in the view

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.