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

Entwickler
  • 255
  • 2
  • 12
bresleveloper
  • 5,940
  • 3
  • 33
  • 47
  • Can you try to rename `function VODCatalogController($scope, $http) {` to `function VODCatalog($scope, $http) {` and `VODCatalogModule.controller("VODCatalogController", VODCatalogController);` to `VODCatalogModule.controller("VODCatalogController", VODCatalog);` – Dmitry Manannikov Aug 06 '13 at 13:55
  • tried it, nothing changed... – bresleveloper Aug 06 '13 at 14:17

2 Answers2

12

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

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
user3334157
  • 171
  • 1
  • 7
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

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
bresleveloper
  • 5,940
  • 3
  • 33
  • 47
  • 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. – Amogh Talpallikar Jan 21 '14 at 11:24
  • 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 – bresleveloper Jan 23 '14 at 08:48
  • 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) – Mohamad Al Asmar Jun 14 '16 at 21:15
  • why FROM the $stateProvider? you should only call it from a click in the view – bresleveloper Jun 15 '16 at 12:08