Utilizing the controller specified in the template that has been included

Within this snippet of code, I am attempting to utilize a controller named FooCtrl that is defined in the included template app/foo.html, using the directive common.script.

angular.module('common.script', []).directive('script', function() {
  return {
    restrict: 'E',
    scope: false,
    compile: function(element, attributes) {
      if (attributes.script === 'lazy') {
        var code = element.text()
        new Function(code)()
      }
    }
  }
})
angular.module('app.templates', ['app/foo.html'])
angular.module("app/foo.html", []).run(function($templateCache) {
  $templateCache.put("app/foo.html",
    "<script data-script=\"lazy\">\n" +
    "   console.log('Before FooCtrl')\n" +
    "angular.module('app').controller('FooCtrl', function($scope) {\n" +
    "console.log('FooCtrl')\n" +
    "})\n" +
    "<\/script>\n" +
    "<div data-ng-controller=\"FooCtrl\">app\/foo.html\n" +
    "<\/div>"
  )
})
angular.module('app', ['common.script', 'app.templates']).controller('ApplicationCtrl', function($scope) {
  console.log('ApplicationCtrl')
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ApplicationCtrl">
  <div data-ng-include="'app/foo.html'"></div>
</div>

Despite my expectations of seeing FooCtrl in the console output, AngularJS throws an error:

Error: [ng:areq] Argument 'FooCtrl' is not a function [...]

I am puzzled as to why this error occurs! The template's code is executed before the exception is raised, indicating that the controller should be defined. How can I rectify this issue?

Answer №1

The main issue at hand is the lazy loading of resources, which presents a challenge in this scenario! There exists an abundance of materials and related discussions on this particular subject.

An effective solution could involve an enhanced common.script directive:

'use strict'

angular.module('common.script', [])

.config(function($animateProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
  angular.module('common.script').lazy = {
    $animateProvider: $animateProvider,
    $controllerProvider: $controllerProvider,
    $compileProvider: $compileProvider,
    $filterProvider: $filterProvider,
    $provide: $provide
  }
})

.directive('script', function() {
  return {
    restrict: 'E',
    scope: {
      modules: '=script'
    },
    link: function(scope, element) {
      var offsets = {}, code = element.text()

      function cache(module) {
        offsets[module] = angular.module(module)._invokeQueue.length
      }

      function run(offset, queue) {
        var i, n
        for (i = offset, n = queue.length; i < n; i++) {
          var args = queue[i], provider = angular.module('common.script').lazy[args[0]]

          provider[args[1]].apply(provider, args[2])
        }
      }

      if (angular.isString(scope.modules)) {
        cache(scope.modules)
      } else if (angular.isArray(scope.modules)) {
        scope.modules.forEach(function(module) {
          cache(module)
        })
      }

      /*jshint -W054 */
      new Function(code)()

      Object.keys(offsets).forEach(function(module) {
        if (angular.module(module)._invokeQueue.length > offsets[module]) {
          run(offsets[module], angular.module(module)._invokeQueue)
        }
      })
    }
  }
})

The only drawback to consider with this approach is that you must specify the module(s) you wish to extend within a script tag:

<script data-script="'app'">
  angular.module('app').controller('FooCtrl', function($scope) {
    console.log('Success!')
  })
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Executing an asynchronous action without linking promises to subsequent actions

Encountered a challenge while using componentWillReceiveProps with redux async action. Below is the code snippet along with an explanation: componentWillReceiveProps(nextProps) { if(nextProps.job.status === 'applied'){ this.showAppliedDial ...

When running npm install, the dist folder is not automatically generated

I found a helpful tutorial at this link for creating a Grafana plugin. However, when I tried copying the code from this link to my test server (without the dist/ folder) and ran npm install, it did not generate a new dist/ folder but created a node_module ...

Retrieve data using the designated key and convert it into JSON format

If I have the following JSON array: [ {"data": [ {"W":1,"A1":"123"}, {"W":1,"A1":"456"}, {"W":2,"A1":"4578"}, {"W":2,"A1":"2423"}, {"W":2,"A1":"2432"}, {"W":2,"A1":"24324" ...

Testing out a login form in Vue framework

Hi there! I recently put together a login form using the Vue.js framework, and now I'm looking to write some tests for my API calls. Although I'm still new to Vue.js, I'm eager to learn more about testing in this environment. Here's th ...

Link that updates periodically linked to an image

My goal is to have a URL change on a timer that is linked to an image. For example, after 10 seconds, I want the URL attached to the image to change without changing the actual image itself. I've been trying to figure out how to modify this code, but ...

Exploring Data in a Tree View Format on a PHP Website

Looking for advice on displaying categories and corresponding subcategories on the left side of my website (built using Php and Javascript). I would like the tree to be movable, similar to the functionality featured on this link: Any suggestions on how I ...

The click() function in jQuery executing only once inside a "for" loop

This is an example of my HTML code: <!DOCTYPE html> <head> <title>Chemist</title> <link href="stylesheet.css" rel="stylesheet"> </head> <body> <h2 id="money"></h2> <table border="1px ...

Is there a way to override the JSON.stringify method within the JSON class of a TypeScript project without using a custom call?

Dealing with a React Native and TypeScript app here. I keep encountering an error from Fabric every week: "JSON.stringify cannot serialize cyclic structures." The frustrating part is that the error seems to pop up randomly, without any specific scenario tr ...

Is there a way for me to modify this carousel so that it only stops when a user hovers over one of the boxes?

I am currently working to modify some existing code to fit my website concept. One aspect I am struggling with is how to make the 'pause' function activate only when a user hovers over one of the li items, preventing the carousel from looping end ...

A guide on utilizing multer-sftp for downloading files

I've been working on this code, but after searching online I still haven't found a way to download a file from the remote server. I can successfully upload files to the server, but downloading them is posing a challenge. var storage = sftpStorag ...

Remove a particular row from a database table

I'm facing an issue with my code. I want to be able to remove a row by clicking on a remove button within that row, but I'm unsure of how to accomplish this. <tbody id="myTable"> <?php if (!isset($_SESSION)){ ...

Obtaining the result from within the .then() block

Through the utilization of Google's API, I am successful in retrieving and displaying nearby places on the console. router.get('/', function (req, res, next) { // Locating nearby establishments googleMapsClient.placesNearby({ ...

New techniques in VueJS 3: managing value changes without using watchers

I am currently working on coding a table with pagination components and I have implemented multiple v-models along with the use of watch on these variables to fetch data. Whenever the perPage value is updated, I need to reset the page value to 1. However, ...

Trigger a modal to open based on a specific condition

I have successfully implemented a default modal from Materialize, but now I am looking to add a conditional opening feature to it. In my application, there is a countdown timer and I want the modal to automatically appear when the countdown reaches a certa ...

The HTML grid is causing an irritating excess space on the right side of my website

After brainstorming an idea, I decided to create this website for testing purposes. However, the grid layout seems to be causing an unwanted margin on the right side of the page that is not associated with any HTML tag, disrupting the zoom functionality. ...

Is there a way to delegate properties in Angular 2+ similar to React?

When working with React, I have found it convenient to pass props down dynamically using the spread operator: function SomeComponent(props) { const {takeOutProp, ...restOfProps} = props; return <div {...restOfProps}/>; } Now, I am curious how I ...

Exploring the Possibilities of Socket.io Integration with Express 4 Across Multiple Pages: Dive Into Socket.io Sample Code

Just to clarify, I came across a similar question on Stack Overflow before posting this. However, the answer there was not clear to me and my query is slightly different. Thus, I am hoping for a more straightforward explanation. The Express Generator sets ...

Is there an easy method for extracting URL parameters in AngularJS?

Hello, I'm new to Angular and coming from a background in PHP and ASP. In those languages, we typically read parameters like this: <html> <head> <script type="text/javascript"> var foo = <?php echo $_GET['foo&apo ...

Creating a dynamic link in Vue JS is a cinch!

I currently have the following code snippet: <b-dropdown text="Select Factory" block variant="primary" class="m-2" menu-class="w-100"> <b-dropdown-item @click="selectedFactory='China'"> ...

Creating a interactive navigation bar with External JSON data in HTML and JavaScript

Is there a way to create a dynamic MenuBar by using an external JSON file? How can I write HTML code to fetch and display JSON data dynamically? What is the process for reading a JSON file? //JSON File = Menu.Json {"data": [{"id": "1", "text": "F ...