3

I am trying to create an angular app which can be shipped and bootstrapped with little to no directives. Ideally you would include the js file:

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

Then put a div on a page:

<div id="myDiv"></div>

And bootstrap the app like:

angular.bootstrap(document.getElementById('myDiv'),['myApp']);

This, needless to say, doesn't work.

See this fiddle to see it working with the ng-* directives in place and this one without.

I guess my question is - is this even possible?

Ideally, I'd like to implement my app similar to Stripe:

<script
  src="https://checkout.stripe.com/v2/checkout.js" class="stripe-button"
  data-key="pk_test_czwzkTp2tactuLOEOqbMTRzG"
  data-amount="2000"
  data-name="Demo Site"
  data-description="2 widgets ($20.00)"
  data-currency="usd"
  data-image="/128x128.png">
</script>

but couldn't find a way to get this to work either. The main goal is to not have to expose the angular specifics to use my app.

4 Answers 4

10

From official docs:

If you need to have more control over the initialization process, you can use a manual bootstrapping method instead. You should not use the ng-app directive when manually bootstrapping your app.

<!doctype html>
<html>
<body>
  <div ng-controller="MyController">
    Hello {{greetMe}}!
  </div>
  <script src="http://code.angularjs.org/snapshot/angular.js"></script>

  <script>
    angular.module('myApp', [])
      .controller('MyController', ['$scope', function ($scope) {
        $scope.greetMe = 'World';
      }]);

    angular.element(document).ready(function() {
      angular.bootstrap(document, ['myApp']);
    });
  </script>
</body>
</html>

Sign up to request clarification or add additional context in comments.

Comments

1

You can also "cheat" this a little bit with using jQuery to add the ng-controller attribute to the div after the fact.

$(function() {
    $('#main_container').attr('ng-controller', 'InventoryController');
    $.when(angular.bootstrap(document.getElementById('main_container'), ["InventoryModule"])).done(function() {
        console.log("app bootstrapped");
    });
});

Fiddle : http://jsfiddle.net/tj24K/

Essentially, though, Angular works by adding directives to templates. If you want perfectly clean templates to start, you'll need to do all the directive adding in jQuery. To me, this seems like more work than it's worth. The whole beauty of Angular is doing away with jQuery selectors.

PS., I also changed your controller to just set the $scope.items instead of returning it.

3 Comments

Yeah I'm really trying to avoid jquery although this seems neat. I could maybe look at jQLite which is bundled in with angular. Doesn't feel so cheaty then. Will try and report back. Will also try looking at the controller factory as Mike P suggested.
ok so I went for: var myelement = document.querySelector('#myDiv'); angular.element(myelement).attr('ng-controller','myCtrl'); angular.bootstrap(myelement,['myApp']); Seems to work quite well. This needs to happen after the #myDiv has been loaded though or we need to wait for the document to be ready. There is a jQLite.ready() function that i'll look at.
@preeve , I agree, avoiding unneeded libraries is a good practice. In this case the same job can be done with angular.element. As you suggested. I added a different answer so people can find it easier.
0

Update: Missed the part of the title that said you wanted to avoid ng-controller.

If you need to add behavior defined in a controller then the easiest way is to just use the ng-controller directive. You can get away with what I wrote below without exposing any angular specifics on your clients. If it's an absolute that you not use ng-controller but still want controller behavior, you'll probably need to dive into the Controller Factory code and see how you can create and attach the scope to your controller method. This seems like more complexity than its worth.

Original Post:

You're bootstrapping the app but you're using a controller that hasn't been added to the HTML elements you're creating.

I'm assuming you're going to inject some HTML, so you should be able to decorate your main DIV element with ng-controller, and then bootstrap away. I'd recommend bootstrapping on that one element vs document, just in case someone is bringing your code into an existing angularjs based site.

http://jsfiddle.net/detLd/1/

<div ng-controller="InventoryController">
    <ul ng-repeat='item in items'>
        <li>{{item.title}}</li>
        <li>{{item.price | currency}}</li>
    </ul>
</div>

You'll want to read through the comments on this page http://docs.angularjs.org/api/angular.bootstrap

Comments

0

You can insert element (directive) into document just before bootstraping application.

<html>
  <body>
    <script src="http://code.angularjs.org/snapshot/angular.js"></script>
    <script type="text/javascript" src="./app.js"></script>
  </body>
</html>

and in app.js

angular
  .element(document)
  .ready(function () {
     angular
      .module('myApp', [])
      .directive('myDirective', function () {
        return {
          template: '<div>my directive 2+2 = {{2+2}} </div>'
        };
      });
    var body = document.getElementsByTagName("body")[0];
    var appElement = document.createElement("my-directive");
    body.appendChild(appElement);
    angular.bootstrap(body, ['myApp']);
  });

https://jsfiddle.net/7dzo7q90/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.