programing

Angular JS: 컨트롤러 및 콘텐츠 로드 지연

newstyles 2023. 3. 10. 21:19

Angular JS: 컨트롤러 및 콘텐츠 로드 지연

이 간단한 시나리오에서는 index.htm과 lazy.htm의 2개의 파일이 있습니다.

index.htm:

var myApp = angular.module('myApp', []);
myApp.controller('embed',function($scope){
    $scope.embed = 'Embedded Controller';
});                  
<div ng-controller="embed">{{embed}}</div>    
<div ng-include="'lazy.htm'"></div>

게으름뱅이.htm

myApp.controller('lazy',function($scope){
    $scope.lazy = 'Lazy Controller';
});
<div ng-controller="lazy">
    {{lazy}}
</div>

결과는 오류입니다. "인수 'lazy'는 함수가 아닙니다. 정의되지 않았습니다."

대신 기능 사용

게으름뱅이.htm

function lazy($scope) {
    $scope.lazy = 'Lazy Controller';
}
<div ng-controller="lazy">
    {{lazy}}
</div>

이 기능은 버전 1.3 베타 14까지 작동합니다.베타 15에서는 글로벌 컨트롤러 기능(https://github.com/angular/angular.js/issues/8296이 삭제되었습니다.

그럼 lazy.htm의 각진 콘텐츠를 동적으로 얻는 더 좋은 방법은 무엇일까요?

갱신:

이 기사(http://ify.io/lazy-loading-in-angularjs))에서 저는 다른 가능한 해결책을 찾았습니다.$controllerProvider를 사용하면 각도 부트스트랩 후에 새로운 컨트롤러를 등록할 수 있습니다.마법처럼 작동한다.v1.3.0-beta에서 테스트 완료.열여덟 살

index.htm:

var myApp = angular.module('myApp', [])
.controller('embed',function($scope){
    $scope.embed = 'Embedded Controller';
})
.config(function($controllerProvider) {
    myApp.cp = $controllerProvider;
});

<div ng-controller="embed">{{embed}}</div>    
<div ng-include="'lazy.htm'"></div>

게으름뱅이.htm

myApp.cp.register('lazy',function($scope){
    $scope.lazy = 'Lazy Controller';
});
<div ng-controller="lazy">
    {{lazy}}
</div>

업데이트 2:

그 밖에 효과가 있는 2가지 대안은 다음과 같습니다.

게으름뱅이.htm

_app = $('[ng-app]').scope();    
_app.lazy = function($scope) {
    $scope.lazy = 'Lazy Controller';
};

또는

var $rootScope = $('[ng-app]').injector().get('$rootScope');        
$rootScope.lazy = function($scope) {
    $scope.lazy = 'Lazy Controller';
}; 

하지만 저는 이 마지막 두 가지 예가 생산에 사용되어서는 안 된다고 생각합니다.

jquery를 $routeProvider 해결과 함께 사용할 수도 있습니다.

app.module

/* Module Creation */
var app = angular.module ('app', ['ngRoute']);

app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){

/*Creating a more synthesized form of service of $ controllerProvider.register*/
app.registerCtrl = $controllerProvider.register;

function loadScript(path) {
  var result = $.Deferred(),
  script = document.createElement("script");
  script.async = "async";
  script.type = "text/javascript";
  script.src = path;
  script.onload = script.onreadystatechange = function (_, isAbort) {
      if (!script.readyState || /loaded|complete/.test(script.readyState)) {
         if (isAbort)
             result.reject();
         else
            result.resolve();
    }
  };
  script.onerror = function () { result.reject(); };
  document.querySelector("head").appendChild(script);
  return result.promise();
}

function loader(arrayName){

    return {
      load: function($q){
                var deferred = $q.defer(),
                map = arrayName.map(function(name) {
                    return loadScript('js/controllers/'+name+".js");
                });

                $q.all(map).then(function(r){
                    deferred.resolve();
                });

                return deferred.promise;
        }
    };
}

$routeProvider  
    .when('/', {
        templateUrl: 'views/foo.html',
        resolve: loader(['foo'])
    })
    .when('/bar',{
        templateUrl: 'views/bar.html',
        controller: 'BarCtrl',
        resolve: loader(['bar'])
    })
    .otherwise({
        redirectTo: document.location.pathname
    });
}]);

/syslog/foo.displays

<section ng-controller='FooCtrl'>
    {{text}}
</section>

js/controllers/foo.disples

/*Here we use the synthesized version of $controllerProvider.register 
to register the controller in view*/
app.registerCtrl('FooCtrl',function($scope){
    $scope.text = 'Test';
});

/syslog/bar.syslog

<section>
    {{text2}}
</section>

js/controllers/bar.disples

app.registerCtrl('BarCtrl',function($scope){
    $scope.text2 = 'Test';
});

///JConfig 파일---------

window.angularApp.config(function ($routeProvider,$controllerProvider,$compileProvider,$provide, azMessages) {

$routeProvider.when('/login', {
             resolve: {
                 load: ['$q', '$rootScope', function ($q, $rootScope) {
                     var deferred = $q.defer();
                     require([

                         //load required Js file here

                ], function () {
                    $rootScope.$apply(function () {
                        deferred.resolve();
                    });
                });
                     return deferred.promise;
                 } ]
             }
         });


  $routeProvider.otherwise({ redirectTo: '/login' });

    window.angularApp.components = {
        controller: $controllerProvider.register,
        service: $provide.service,
        directive: $compileProvider.directive
    }

//컨트롤러 선언

angularApp.components.controller('DiscussionController',[function(){

}]);

처음에 나는 André Betiolo의 대답을 이용했다.단, Ajax 로딩이 논블로킹이기 때문에 스크립트가 로드되기 전에 뷰가 컨트롤러를 요구할 수 있기 때문에 항상 동작하는 것은 아닙니다.

해결책으로 모든 스크립트가 정상적으로 로드될 때까지 함수가 돌아가지 않도록 했습니다.이것은 다소 해킹적이지만 해결을 완료하기 전에 로드가 성공했는지 확인합니다.또, 복수의 컨트롤러를 로드할 수도 있습니다.

app.module

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

app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){

    /*Creating a more synthesized form of service of $ controllerProvider.register*/
    app.registerCtrl = $controllerProvider.register;

    //jquery to dynamically include controllers as needed
    function controllers(controllers){
        var numLoaded = 0;
        for (i = 0; i < controllers.length; i++) {
            $.ajaxSetup({async:false});
            $.getScript('js/controllers/' + controllers[i] + '.js').success(function(){
                numLoaded++;
                if (numLoaded == controllers.length) {
                    return true; //only return after all scripts are loaded, this is blocking, and will fail if all scripts aren't loaded.
                }
            });
        }
    }

    $routeProvider
        .when('/', {
            templateUrl: 'views/foo.html',
            resolve: {
                load: function () {
                    controllers(['foo'])
                }
            }
        })
        .when('/bar',{
            templateUrl: 'views/bar.html',
            controller: 'BarCtrl',
            resolve: {
                load: function () {
                    controllers(['bar','foo']) //you can load multiple controller files
                }
            }
        })
        .otherwise({
            redirectTo: document.location.pathname
        });
}]);

/syslog/foo.displays

<section ng-controller='FooCtrl'>
    {{text}}
</section>

/syslog/bar.syslog

<section ng-controller='BarCtrl'>
    {{text2}}
</section>
<section ng-controller='FooCtrl'>
    {{text}}
</section>

/controllers/bar.disples

app.registerCtrl('BarCtrl',function($scope){
    $scope.text2 = 'Test';
});

순수한 Angular를 가질 수 있습니다.JS의 부하가 느리다.

"Lazy Service" 작성:

var ng = angular.module('app');

ng.factory('lazyService', [ '$http', function($http) {
    var jsPath = 'js/${ name }.js';
    var promisesCache = {};

    return {
        loadScript: function(name) {
            var path = jsPath.replace('${ name }', name);
            var promise = promisesCache[name];
            if (!promise) {
                promise = $http.get(path);
                promisesCache[name] = promise;

                return promise.then(function(result) {
                    eval(result.data);
                    console.info('Loaded: ' + path);
                });
            }

            return promise;
        }
    }
}]);

다음으로 설정을 정의합니다.

var ng = angular.module('app', [ 'ngRoute' ]);

ng.config([ '$routeProvider', '$controllerProvider', '$provide', function($routeProvider, $controllerProvider, $provide) {
    // Lazy loading
    ng.lazy = {
        controller: $controllerProvider.register,
        //directive: $compileProvider.directive,
        //filter: $filterProvider.register,
        factory: $provide.factory,
        service: $provide.service
    }

    $routeProvider
    .when('/', {
        templateUrl: 'view/home.html'
    })
    .when('/vendor', {
        templateUrl: 'view/vendor.html',
        resolve: {
            svc: [ 'lazyService', function(lazyService) {
                return lazyService.loadScript('services/vendor');
            }],
            ctrl: [ 'lazyService', function(lazyService) {
                return lazyService.loadScript('controllers/vendor');
            }]
        }
    });
. . .

"js/services/vendor.js"에서 다음과 같이 서비스를 만듭니다.

var ng = angular.module('app');
ng.lazy.service('vendorService', [ function() {
. . .

"js/controllers/vendor.js"에서 다음과 같이 컨트롤러를 만듭니다.

var ng = angular.module('app');
ng.lazy.controller('vendorController', [ function() {
. . .

의 "resolve" 속성은 루트 로드 전에 해결해야 할 약속을 정의합니다.

가장 좋은 방법은 명령어를 사용하여 컨트롤러와 템플릿을 적절한 타이밍에 결합하는 것입니다.현재 바인딩은 발생하지 않습니다.lazy.htm두 번째 예시와 같이 글로벌 함수를 선언하지 않는 한 적절한 타이밍에 실행할 수 있습니다.

이상적 - 각도에서는 HTML과 JS를 분리하도록 강제합니다.새로운 버전에서는 이것이 더 자주 적용될 수 있습니다.

require를 사용해야 할 수 있습니다.JS http://solutionoptimist.com/2013/09/30/requirejs-angularjs-dependency-injection/

속임수를 써서라도 해 볼래?

ng-controller-controller="'lazy'"

또는

HTML에서

ng-controller-controller="myObject.controller"

어디선가 주입하다

$scope.myObject.controller = $controller('lazy', {$scope: $scope})

ARI 플러그인을 Angular JS에 사용해 보십시오.이 기능을 사용하면 컨트롤러 스크립트를 필요에 따라 느리게 로드할 수 있습니다.

Directive를 사용하여 컨트롤러를 로드할 수도 있습니다.

예를 들어 다음과 같습니다.

https://gist.github.com/raphaelluchini/53d08ed1331e47aa6a87

샘플 코드를 보내드립니다.저는 잘 되고 있어요.확인 부탁드립니다.

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

/* Module Creation */
var app = angular.module('app', ['ngRoute']);

app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) {

app.register = {
    controller: $controllerProvider.register,
    //directive: $compileProvider.directive,
    //filter: $filterProvider.register,
    //factory: $provide.factory,
    //service: $provide.service
};


//    so I keep a reference from when I ran my module config
function registerController(moduleName, controllerName) {
    // Here I cannot get the controller function directly so I
    // need to loop through the module's _invokeQueue to get it
    var queue = angular.module(moduleName)._invokeQueue;
    for (var i = 0; i < queue.length; i++) {
        var call = queue[i];
        if (call[0] == "$controllerProvider" &&
           call[1] == "register" &&
           call[2][0] == controllerName) {
            app.register.controller(controllerName, call[2][1]);
        }
    }
}


var tt = {
    loadScript:
function (path) {
    var result = $.Deferred(),
    script = document.createElement("script");
    script.async = "async";
    script.type = "text/javascript";
    script.src = path;
    script.onload = script.onreadystatechange = function (_, isAbort) {
        if (!script.readyState || /loaded|complete/.test(script.readyState)) {
            if (isAbort)
                result.reject();
            else {
                result.resolve();
            }
        }
    };
    script.onerror = function () { result.reject(); };
    document.querySelector(".shubham").appendChild(script);
    return result.promise();
}
}

function stripScripts(s) {
    var div = document.querySelector(".shubham");
    div.innerHTML = s;
    var scripts = div.getElementsByTagName('script');
    var i = scripts.length;
    while (i--) {
        scripts[i].parentNode.removeChild(scripts[i]);
    }
    return div.innerHTML;
}


function loader(arrayName) {
    return {
        load: function ($q) {
            stripScripts(''); // This Function Remove javascript from Local
            var deferred = $q.defer(),
            map = arrayName.map(function (obj) {
                return tt.loadScript(obj.path)
                .then(function () {
                    registerController(obj.module, obj.controller);
                })
            });

            $q.all(map).then(function (r) {
                deferred.resolve();
            });
            return deferred.promise;
        }
    };
};



$routeProvider
    .when('/first', {
        templateUrl: '/Views/foo.html',
        resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' },
            { controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }])
    })

    .when('/second', {
        templateUrl: '/Views/bar.html',
        resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' },
        { controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }])
    })
    .otherwise({
        redirectTo: document.location.pathname
        });
}])

HTML 페이지:

<body ng-app="app">

<div class="container example">
    <!--ng-controller="testController"-->

    <h3>Hello</h3>

    <table>
        <tr>
            <td><a href="#/first">First Page </a></td>
            <td><a href="#/second">Second Page</a></td>
        </tr>
    </table>




        <div id="ng-view" class="wrapper_inside" ng-view>
        </div>
    <div class="shubham">
    </div>
</div>

고마워

언급URL : https://stackoverflow.com/questions/25168593/angularjs-lazy-loading-controllers-and-content