最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - Javascript not accessible from inside Angular ui-view - Stack Overflow

programmeradmin3浏览0评论

I have a main template (index.html) with an Angular ui-view. Inside this main template I import a bunch of Javascript files. I expect these files to be available to the content inside the html templates that will be loaded inside the ui-view, but the JS functions are seemingly inaccessible.

/sample-app/index.html:

<html ng-app="otr">
<head></head>
<body>
    <div ui-view></div>

    <!-- JS imports -->
    <script src="//code.jquery/jquery-2.1.3.min.js"></script>
    <script src=".3.4/js/bootstrap.min.js"></script>

    <!-- Angular Dependencies -->
    <script src=".4.0-rc.1/angular.min.js"></script>
    <script src=".4.0-rc.1/angular-route.min.js"></script>
    <script src=".4.0-rc.1/angular-cookies.min.js"></script>
    <script src=".2.14/angular-ui-router.min.js"></script>

    <!-- Custom scripts -->
    <script src="/sample-app/js/login.js"></script>

    <!-- Angular app scripts -->
    <script src="app/app.js"></script>
    <script src="app/services/authentication.service.js"></script>
    <script src="app/services/flash.service.js"></script>
    <script src="app/mon/cases-model.js"></script>

    <script src="app/home/home.controller.js"></script>
    <script src="app/login/login.controller.js"></script>
    <script src="app/register/register.controller.js"></script>        

</body>
</html>

/sample-app/js/login.js

$(function() {

    $('#login-form-link').click(function(e) {
        $("#login-form").delay(100).fadeIn(100);
        $("#register-form").fadeOut(100);
        $('#register-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });
    $('#register-form-link').click(function(e) {
        console.log('Inside login.js REGISTER');
        $("#register-form").delay(100).fadeIn(100);
        $("#login-form").fadeOut(100);
        $('#login-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });

});

/sample-app/app/app.js:

(function () {
    'use strict';

    angular.module('otr', [
        'ngRoute',
        'ngCookies',
        'ui.router',
    ])
        .config(config)
        .run(run);

    function config($stateProvider, $urlRouterProvider, $httpProvider) {

        $stateProvider
            .state('otr', {
                url: '',
                abstract: true
            })
            .state('login', {
                url: '/login',
                controller: 'LoginController as vm',
                templateUrl: 'app/login/login.view.html'
            })
            .state('register', {
                url: '/register',
                controller: 'RegisterController as vm',
                templateUrl: 'app/register/register.view.html'
            })
            .state('home', {
                url: '/',
                controller: 'HomeController as vm',
                templateUrl: 'pages/home2.view.html'
            })
        ;

        $urlRouterProvider.otherwise('/login');
        $httpProvider.defaults.withCredentials = true;
    }

    function run($rootScope, $location, $cookies, $http) {
        // keep user logged in after page refresh
        $rootScope.globals = $cookies.get('globals') || {};

        $rootScope.$on('$locationChangeStart', function (event, next, current) {
            // redirect to login page if not logged in and trying to access a restricted page
            var restrictedPage = $.inArray($location.path(), ['/login', '/register']) === -1;
            var loggedIn = $rootScope.globals.currentUser;
            if (restrictedPage && !loggedIn) {
                $location.path('/login');
            }
        });
    }

})();
  • The ui-view content loads just fine, but without the JS functions being called.
  • If I copy/paste the content directly into index.html, everything works as expected
  • If I place the JS import inside the partial template, that works as well.

What am I missing?

I have a main template (index.html) with an Angular ui-view. Inside this main template I import a bunch of Javascript files. I expect these files to be available to the content inside the html templates that will be loaded inside the ui-view, but the JS functions are seemingly inaccessible.

/sample-app/index.html:

<html ng-app="otr">
<head></head>
<body>
    <div ui-view></div>

    <!-- JS imports -->
    <script src="//code.jquery./jquery-2.1.3.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn./bootstrap/3.3.4/js/bootstrap.min.js"></script>

    <!-- Angular Dependencies -->
    <script src="https://ajax.googleapis./ajax/libs/angularjs/1.4.0-rc.1/angular.min.js"></script>
    <script src="https://code.angularjs/1.4.0-rc.1/angular-route.min.js"></script>
    <script src="https://code.angularjs/1.4.0-rc.1/angular-cookies.min.js"></script>
    <script src="https://cdnjs.cloudflare./ajax/libs/angular-ui-router/0.2.14/angular-ui-router.min.js"></script>

    <!-- Custom scripts -->
    <script src="/sample-app/js/login.js"></script>

    <!-- Angular app scripts -->
    <script src="app/app.js"></script>
    <script src="app/services/authentication.service.js"></script>
    <script src="app/services/flash.service.js"></script>
    <script src="app/mon/cases-model.js"></script>

    <script src="app/home/home.controller.js"></script>
    <script src="app/login/login.controller.js"></script>
    <script src="app/register/register.controller.js"></script>        

</body>
</html>

/sample-app/js/login.js

$(function() {

    $('#login-form-link').click(function(e) {
        $("#login-form").delay(100).fadeIn(100);
        $("#register-form").fadeOut(100);
        $('#register-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });
    $('#register-form-link').click(function(e) {
        console.log('Inside login.js REGISTER');
        $("#register-form").delay(100).fadeIn(100);
        $("#login-form").fadeOut(100);
        $('#login-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });

});

/sample-app/app/app.js:

(function () {
    'use strict';

    angular.module('otr', [
        'ngRoute',
        'ngCookies',
        'ui.router',
    ])
        .config(config)
        .run(run);

    function config($stateProvider, $urlRouterProvider, $httpProvider) {

        $stateProvider
            .state('otr', {
                url: '',
                abstract: true
            })
            .state('login', {
                url: '/login',
                controller: 'LoginController as vm',
                templateUrl: 'app/login/login.view.html'
            })
            .state('register', {
                url: '/register',
                controller: 'RegisterController as vm',
                templateUrl: 'app/register/register.view.html'
            })
            .state('home', {
                url: '/',
                controller: 'HomeController as vm',
                templateUrl: 'pages/home2.view.html'
            })
        ;

        $urlRouterProvider.otherwise('/login');
        $httpProvider.defaults.withCredentials = true;
    }

    function run($rootScope, $location, $cookies, $http) {
        // keep user logged in after page refresh
        $rootScope.globals = $cookies.get('globals') || {};

        $rootScope.$on('$locationChangeStart', function (event, next, current) {
            // redirect to login page if not logged in and trying to access a restricted page
            var restrictedPage = $.inArray($location.path(), ['/login', '/register']) === -1;
            var loggedIn = $rootScope.globals.currentUser;
            if (restrictedPage && !loggedIn) {
                $location.path('/login');
            }
        });
    }

})();
  • The ui-view content loads just fine, but without the JS functions being called.
  • If I copy/paste the content directly into index.html, everything works as expected
  • If I place the JS import inside the partial template, that works as well.

What am I missing?

Share Improve this question edited May 4, 2015 at 3:51 AlexG asked May 1, 2015 at 22:15 AlexGAlexG 1,6162 gold badges18 silver badges26 bronze badges 2
  • Can you post more detail about what you have inside of app.js? I may be assuming things about your code that I should not. – Michael Hays Commented May 1, 2015 at 22:47
  • Instead of writing a bunch of jQuery to do your animations, use ng-animate. It will make your life easier and de-speghetti some of your code. – Martin Commented May 2, 2015 at 9:50
Add a ment  | 

7 Answers 7

Reset to default 0

If you want to access stuff outside the , try to create a controller, something like this,

<body>
    <div ng-controller="MainCtrl">
      <div ui-view></div>
      <script src="app/app.js"></script>
    </div>
</body>

Without seeing your project structure it's hard to know for sure, but I suspect that you need to refer to your javascript files using absolute paths rather than relative paths.

EG:

<script src="/app/app.js"></script>

I say this because most AngularJS projects store their views in a sub-folder, and when the template gets loaded the relative paths bee invalid because they are relative to the root of the project/index.html file and not the active view.

You should declare the app name using ng-app, then associate a controller with an element in the HTML. I would suggest this tutorial because you are missing few of the basics.

You need to do something like this:

<!DOCTYPE html>
<html ng-app="myapp" lang="en">
<head>
    <script type="text/javascript" src="js/app.js"></script>
</head>
<body>
    <div ng-controller="MyCtrl"></div>
</body>
</html>

app.js:

(function () {
    var app = angular.module('myapp', []);
    app.controller("MyCtrl", function($scope){
        $scope.foo = function(){};
        this.foo2 = function(){};
    })
})();

Presumably, you have a statement somewhere in app.js that looks like this:

angular.module('MyApp', []);

You will need to manually bootstrap your application. If you have any ng-app= markup in your html, remove it -- make sure app.js is the very last script, and add the following to the end of app.js:

angular.element(document).ready(function() {
  angular.bootstrap(document, ['MyApp']);
});

If you didn't have ng-app in your markup, then you wouldn't have seen anything anyway, as ng-app is the key that tells angular where it should integrate with your page. And ng-app should not be applied until all of the scripts are loaded.

But even if you had it, it still would have given you an error that the directive is not defined. The reason is that angular.js will begin executing as soon as it is loaded. But the code you've written which attaches the directive to your module has not gotten a chance to execute. Very specifically, it means that there is not yet a directive called 'ui-view' defined in your application.

The reason angular code seems to just work when you put it into index.html is that angular is kind enough to wait for the DOM to be ready before actually trying to hook up ponents, and that means that any inline scripts have already gotten a chance to execute.

Keep this bootstrapping trick in your bag, as you'll be using it often.

I gave up on trying to get the JavaScript to load and the ui-view to recognize it. I ultimately solved this by creating an Angular directive that duplicated the function of the JavaScript.

Directive:

angular.module('otr')
    .directive('loginForm', loginFormDirective)
    .directive('registerForm', registerFormDirective)
;

function loginFormDirective() {
    return function(scope, element, attrs) {

        element.bind('click', function() {
            console.log('element: ', element[0].id);
            console.log('attributes: ', attrs);

            $('#' + attrs.loginForm).delay(100).fadeIn(100);
            $("#register-form").fadeOut(100);
            $('#register-form-link').removeClass('active');
            $('#' + element[0].id).addClass('active');
        })
    }
}

function registerFormDirective() {
    return function(scope, element, attrs) {

        element.bind('click', function() {
            $('#' + attrs.registerForm).delay(100).fadeIn(100);
            $("#login-form").fadeOut(100);
            $('#login-form-link').removeClass('active');
            $('#' + element[0].id).addClass('active');
        })
    }
}

My view now has the following code snippet:

<div class="row">
    <div class="col-xs-6">
        <a href="#" class="active" id="login-form-link" login-form="login-form">Login</a>
    </div>
    <div class="col-xs-6">
        <a href="#" id="register-form-link" register-form="register-form">Register</a>
    </div>
</div>

Thanks to all of you who took the time to read my question and post answers!

This is a super late response, but I ran into this same exact issue myself. I have solved this by including the external js libraries before including Angular and Angular UI Router.

Just like the OP, my project consisted of an index.html as well as a ui-view. The partials load into the ui-view properly, but the external js libraries do not take effect inside the partial via ui-view. If the contents from the partial are placed into the index.html, everything works perfectly.

Scripts changed from

<!-- AngularJS -->
<script type="text/javascript" src="node_modules/angular/angular.min.js"></script>
<script type="text/javascript" src="node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="dist/ponents.js" type="text/javascript"></script>

<!-- Custom JS Libries -->
<script src="dist/js/custom.js" type="text/javascript"></script>  

Scripts changed to

<!-- Custom JS Libries -->
<script src="dist/js/custom.js" type="text/javascript"></script>

<!-- AngularJS -->
<script type="text/javascript" src="node_modules/angular/angular.min.js"></script>
<script type="text/javascript" src="node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="dist/ponents.js" type="text/javascript"></script> 

Final Oute and working

<!DOCTYPE html>
<html dir="ltr" data-config='{"style": "calico"}'>
<head>
    <link rel="stylesheet" href="dist/all.css">
</head>

<body ng-app="MyApp">

    <div ui-view></div>

    <!-- Custom JS Libries -->
    <script src="dist/js/custom.js" type="text/javascript"></script>

    <!-- AngularJS -->
    <script type="text/javascript" src="node_modules/angular/angular.min.js"></script>
    <script type="text/javascript" src="node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
    <script src="dist/ponents.js" type="text/javascript"></script> 

</body>
</html>

This is how i get it solved.

  1. In your app.js, create is on controller,
  2. add the controller name to ur index body
  3. the convert the template js to a method.
  4. then create a scope method in your app.js controller.
  5. In the scope method, call the template js method
  6. Inside the ui-view html template or ur dashboard, use ng-init to call the scope method of your app.js controller using

Here is the working example:

index.html

<!DOCTYPE html>
<!--[if lt IE 7]>      <html lang="en" ng-app="zeusWeb" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html lang="en" ng-app="zeusWeb" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html lang="en" ng-app="zeusWeb" class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" ng-app="zeusWeb" class="no-js"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Screening Manager</title>
  <meta name="keywords" content="education, institution, management, portal,screening,application">
  <meta name="description" content="education, institution, management, portal,screening,application">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
  <meta name="author" content="K-Devs System Solutions">
  <meta name="owner" content="Kazeem Olanipekun">
  <meta name="verified by" content="K-Devs System Solutions">
  <meta name="googlebot" content="noodp">
  <meta name="google" content="translate">
  <meta name="revisit-after" content="1 month">
  <!-- build:css css/main.css-->
  <!-- bower:css -->
  <link rel="stylesheet" href="bower_ponents/angular-loading-bar/build/loading-bar.css" />
  <link rel="stylesheet" href="bower_ponents/font-awesome/css/font-awesome.css" />
  <link rel="stylesheet" href="bower_ponents/bootstrap/dist/css/bootstrap.css" />
  <link rel="stylesheet" href="bower_ponents/bootstrap-daterangepicker/daterangepicker.css" />
  <link rel="stylesheet" href="bower_ponents/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.css" />
  <link rel="stylesheet" href="bower_ponents/animate.css/animate.css" />
  <link rel="stylesheet" href="bower_ponents/iCheck/skins/flat/blue.css" />
  <link rel="stylesheet" href="bower_ponents/nprogress/nprogress.css" />
  <link rel="stylesheet" href="bower_ponents/bootstrap-progressbar/css/bootstrap-progressbar-3.3.4.css" />
  <link rel="stylesheet" href="bower_ponents/switchery/dist/switchery.css" />
  <!--endbower-->
  <!--custom:css-->
  <link href="template.css" rel="stylesheet">
  <link rel="stylesheet" href="app.css">
  <!-- endcustom  css-->
  <!-- endbuild -->
  <link rel="shortcut icon" href="images/screening.ico" type='image/x-icon'/>
  <link rel="icon" href="images/screening.ico" type="image/x-icon"/>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn./html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn./respond/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body data-ng-controller="zeusWebCtrl" class="nav-md footer_fixed">
  <!--[if lt IE 7]>
      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy./">upgrade your browser</a> to improve your experience.</p>
  <![endif]-->

  <data ui-view ng-cloak></data>

  <!-- build:js js/vendors.js-->
  <!-- bower:js -->
  <script src="bower_ponents/jquery/dist/jquery.js"></script>
  <script src="bower_ponents/angular/angular.js"></script>
  <script src="bower_ponents/angular-mocks/angular-mocks.js"></script>
  <script src="bower_ponents/angular-bootstrap/ui-bootstrap-tpls.js"></script>
  <script src="bower_ponents/angular-ui-router/release/angular-ui-router.js"></script>
  <script src="bower_ponents/angular-loading-bar/build/loading-bar.js"></script>
  <script src="bower_ponents/bootstrap/dist/js/bootstrap.js"></script>
  <script src="bower_ponents/moment/moment.js"></script>
  <script src="bower_ponents/bootstrap-daterangepicker/daterangepicker.js"></script>
  <script src="bower_ponents/jquery-mousewheel/jquery.mousewheel.js"></script>
  <script src="bower_ponents/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js"></script>
  <script src="bower_ponents/iCheck/icheck.js"></script>
  <script src="bower_ponents/nprogress/nprogress.js"></script>
  <script src="bower_ponents/bootstrap-progressbar/bootstrap-progressbar.js"></script>
  <script src="bower_ponents/transitionize/dist/transitionize.js"></script>
  <script src="bower_ponents/fastclick/lib/fastclick.js"></script>
  <script src="bower_ponents/switchery/dist/switchery.js"></script>
  <!-- endbower -->
  <!-- endbuild -->


  <!-- build:js js/main.js-->
  <!-- code inclusion-->
  <script src="template.js"></script>
  <script src="scripts/index.js"></script>
  <script src="scripts/dashboard/dashboard.js"></script>
  <script src="app.js"></script>
  <!--end inclusion -->
  <!-- endbuild -->

</body>
</html>

here is the app.js

'use strict';
// Declare app level module which depends on views, and ponents
var zeusWeb=angular.module('zeusWeb', ['ui.router', 'angular-loading-bar','dashboard']);
zeusWeb.config(['$stateProvider', '$urlRouterProvider','cfpLoadingBarProvider',function ($stateProvider, $urlRouterProvider,cfpLoadingBarProvider) {

  $urlRouterProvider.otherwise("/");
  /**
   *   State for the very first page of the app. This is the home page .
   */
  $stateProvider.state('home', {
    url: "/",
    templateUrl: 'views/dashboard/dashboard.html',
    controller: 'dashboardCtrl'
  });
/*
  $stateProvider.state('dashboard', {
        url:'/dashboard',
        templateUrl: 'views/dashboard/dashboard.html',
        controller: 'dashboardCtrl',
        controllerAs:'vm'
  });*/

/*
  $stateProvider.state('dashboard', {
    views:{
      'body':{
        url:'/embed',
        templateUrl: 'view1/embed.html',
        controller: 'embed',
        controllerAs:'vm'
      }
    }
  });*/

}]);
zeusWeb.controller('zeusWebCtrl',['$scope',function ($scope) {
  $scope.test = "Testing";
  $scope.appTemplate=function () {
  template();
  };

}]);

here is the embed ui-view dashboard.html

<div  class="container body">
    <div class="main_container">
        <!--sidebar-->
        <section  data-ng-include="'views/dashboard/sidebar-nav.html'" data-ng-controller="sideBarCtrl as vm"></section>
        <!--sidebar-->

        <!-- top navigation -->
        <section  data-ng-include="'views/dashboard/header.html'"></section>
        <!-- /top navigation -->

        <!-- page content -->
        <div class="right_col" role="main" ui-view="body">
            hey
          <!--  <script>template();</script>-->
        </div>
        <!-- /page content -->
        <!--footer-->
        <section  data-ng-include="'views/dashboard/footer.html'"></section>
        <!--footer-->
    </div>
</div>
<div data-ng-init="$parent.appTemplate()"></div>

Please note that if you are having an asynchronous inject sidebars html based on roles. make sure you have a default sidebar html that will put this insted of the dashboard and also make sure that the default sidebar will be loaded last after all other sidebars has loaded successfully.

in my case, here is a sample example of the sidebars.

school admin html sidebar

<div  class="menu_section">
    <h3>Live On</h3>
    <ul class="nav side-menu">
        <li><a><i class="fa fa-bug"></i> Additional Pages <span class="fa fa-chevron-down"></span></a>
            <ul class="nav child_menu">
                <li><a href="e_merce.html">E-merce</a></li>
                <li><a href="projects.html">Projects</a></li>
                <li><a href="project_detail.html">Project Detail</a></li>
                <li><a href="contacts.html">Contacts</a></li>
                <li><a href="profile.html">Profile</a></li>
            </ul>
        </li>
        <li><a><i class="fa fa-windows"></i> Extras <span class="fa fa-chevron-down"></span></a>
            <ul class="nav child_menu">
                <li><a href="page_403.html">403 Error</a></li>
                <li><a href="page_404.html">404 Error</a></li>
                <li><a href="page_500.html">500 Error</a></li>
                <li><a href="plain_page.html">Plain Page</a></li>
                <li><a href="login.html">Login Page</a></li>
                <li><a href="pricing_tables.html">Pricing Tables</a></li>
            </ul>
        </li>
        <li><a><i class="fa fa-sitemap"></i> Multilevel Menu <span class="fa fa-chevron-down"></span></a>
            <ul class="nav child_menu">
                <li><a href="#level1_1">Level One</a>
                <li><a>Level One<span class="fa fa-chevron-down"></span></a>
                    <ul class="nav child_menu">
                        <li class="sub_menu"><a href="level2.html">Level Two</a>
                        </li>
                        <li><a href="#level2_1">Level Two</a>
                        </li>
                        <li><a href="#level2_2">Level Two</a>
                        </li>
                    </ul>
                </li>
                <li><a href="#level1_2">Level One</a>
                </li>
            </ul>
        </li>
        <li><a href="javascript:void(0)"><i class="fa fa-laptop"></i> Landing Page <span class="label label-success pull-right">Coming Soon</span></a></li>
    </ul>
</div>

then, let assume that is the last sidebar of the user, then you then call the default sidebar to call the function

default sidebar html

<div data-ng-init="$parent.appTemplate()"></div>`enter code here

发布评论

评论列表(0)

  1. 暂无评论