Sander Verhagen
Sander Verhagen

Reputation: 9118

Embedding AngularJS view

I have an AngularJS application that I believe is essentially pretty typical (alike many of the examples).

<html ng-app="myApp" ...
<body>
...
    <div class="main" ng-view></div>
    ...

There's a $routeProvider that I've set up with a whole lot of whens to direct users to a view (template partial with a controller), such as:

$routeProvider.when('/incident/:identifier', {templateUrl:'incident.html', controller:"IncidentCtrl"});

This is all working fine. Users can go back and forth between views.

Now, let's say I have a view for an "incident". It has a form with properties of the "incident". (You can change values in the form and "Save", which is besides the point here.) I have the following requirements:

  1. "Add work order" button below the existing form
  2. When button clicked, a form (partial) is loaded below the existing form to enter details for a new "work order"
  3. "Save" button as part of the loaded form (partial) will save the new "work order"
  4. The form (partial) is closed, unloaded or at least visually removed
  5. Possibly go back to 2. to repeat (to add subsequent "work orders")

For the form that is loaded below the existing form I would like to reuse an existing template partial with its subsequent controller, which I'm already using for the top-level ng-view elsewhere. But I've gone down a few roads to implement this at no avail; ng-include seems to not work, as it is pretty static and does not allow for much of a lifecycle on the embedded element. Also, it seems hard to load it dynamically, which means it's gonna be loaded before the "Add work order" button is ever clicked. Could someone point me to a workable strategy? Clearly my goal is to promote reuse of existing template partial and controller, without always having the user to move between views. Much appreciated.


Edit: elaborating: I'm not happy (yet) with any ng-include ideas that I've seen so far, since:

Upvotes: 3

Views: 3170

Answers (2)

Chandermani
Chandermani

Reputation: 42669

I would try to address your concerns with ng-include

There would be a bunch of them if I had more than just a single kind of view to embed. They would all get loaded ahead of being shown for no good reason; overkill

ng-if can help you here. This directive would not load DOM till the condition becomes true. And it also destroys the DOM when the condition becomes false. So something like

    <div ng-if='conditionwhenthepartialshouldbeshown'>
      <ng-include src='templateName'  ng-init='model=parent.someProperty'/>
    </div>

I do not know how to parameterize the embedded views in the same way I can pass $routeParams from the $routeProvider

You can use ng-init for passing some parameters when the view is loaded. Check documentation

I am uncomfortable of too much sharing between parent and child scopes

ng-init can help here again. You can create a property on child scope and pass it the parent scope value in ng-init

I have no way to cleanly recreate the controller for subsequent "adds"

ng-if does this for you.

Upvotes: 5

D.Evangelista
D.Evangelista

Reputation: 6543

The way that I found to reproduce this behavior was using Two controllers: One for your "main" view and one for your partial view.

In your controllers file

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

controllers.controller('IncidentCtrl', ['$scope', function($scope) {
    // Incident Ctrl Body
    $scope.showForm = false;
    $scope.toggleForm = function() {
        $scope.showForm = !$scope.showForm;
    }
}]);

controllers.controller('WorkOrderCtrl', ['$scope', function($scope) {
    // Partial Form controller
    // This controller can talk with $scope from IncidentCtrl 
    //    using the $scope.$parent.$parent

    $scope.save = function() {
        // ...
        $scope.$parent.$parent.showForm = false;
    }
}]);

And your views:

<!-- incident.html -->
<button data-ng-click="toogleForm()"> Toggle Form </button>
<div data-ng-show="showForm">
    <div ng-include src="'path/to/_work_order.html'"></div>
</div>

<!-- _work_order.html -->
<div data-ng-controller="WorkOrderCtrl">
   <!-- view body -->
   <button data-ng-click="save()"> Save </button>
</div>

Upvotes: 2

Related Questions