madflow madflow - 3 months ago 17
AngularJS Question

Change registered component in bootstrap period in Angular 1.5

Consider the following code:

<!doctype html>
<html>
<body>

<main></main>

<script src="http://code.angularjs.org/snapshot/angular.js"></script>
<script src="script.js"></script>

</body>
</html>


script.js

window.name = "NG_DEFER_BOOTSTRAP!";

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

angular.module('myApp')
.component('main', {
controller: function () {
this.greeting = 'World';
},
template: '<h1>Hello {{ $ctrl.greeting }} from main</h1>'
});

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

// Customizing comes here
// Should change the template to "Hello World from custom main"

angular.resumeBootstrap();
});


http://plnkr.co/edit/xftcWVXdFslptTGJiNM7?p=preview

I have a base application and a custom "slot" on the server side, where it is possible to insert code between
angular.bootstrap(document, ['myApp']);
and
angular.resumeBootstrap();
in order to add custom logic to the app.

This works fine when adding new modules to the app, for instance.

Is there a way to change already registered components? I basically want to be able to change the signature of the registered component object.

In the mininmal example above and in the plunkr I simply want to change the "template" of the already registered component
main
to something else.

Example edited: Added controller and amended plunkr

Answer

I have to say I haven't seen such use case before. Usually we'd just decorate directives... but here's one scary-looking-hacky-feeling workaround.

Change your script injection logic in a way you inject JSON array containing everything you want to override, having name and obj pairs, where name is component you want to modify and obj object contains any properties you want to add or replace.

Something like following.

window.name = "NG_DEFER_BOOTSTRAP!";

var myApp = angular.module('myApp', []);    
myApp.component('main', {
  template: '<h1>Initially nothing to bind :(</h1>'
});

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

  // Customizing comes here in following format
  var json = [{
    name: 'main',
    obj: {
      controller: function() {
        this.goof = 'Yo!';
      },
      template: '<span>{{ $ctrl.goof }}</span>'
    }
  }];

  // Scary looking override logic !!1
  myApp._invokeQueue.forEach(function(current) { 
    var obj = current[2];
    var name = obj[0];
    var replacement = _.findWhere(json, { name: name });

    if (replacement) {
      for (var key in replacement.obj) {
        obj[1][key] = replacement.obj[key];
      }
    }
    current = obj;
  });

  angular.resumeBootstrap();
});

Yo

Forked plunker here http://plnkr.co/edit/XQ1vZM

Comments