0

What I need

A chain of screens that each open the next screen on a button click. Each previous screen must be collapsed and the new screen must be added by loading a partial view from the MVC backend.

What I have

An AngularJS controller with the following function:

self.AddChild = function (uri, targetContainerId, collapseTitle, breadCrumbContainerId) {
    var target = $("#" + targetContainerId);

    if (target != 'undefined' && target != undefined && target.length > 0) {
        apiService.Get(uri).then(function (viewData) {
            self.CollapsePreviousChild(self.ChildCount);

            // Increase childcount by 1
            self.ChildCount += 1;

            // Set HTML data
            var html = '<div id="collapsibleScreen-"' + self.ChildCount + ' class="open">' + viewData + '</div>';

            target.html(html);

            // Update screens collapse status
            self.UpdateScreenBreadCrumb(collapseTitle, breadCrumbContainerId);
        });
    };
}

The UpdateScreenBreadCrumb function works and is otherwise unrelated.

It is called (for instance) like this:

self.AddChild("/Partials/View1", "targetContainer", "View", "breadCrumbContainer");

What it does

The content of the View, a form, is loaded, the breadcrumb is updated correctly.

What I need fixed

On the partial view that was loaded, there is a button defined like this:

<button class="btn btn-primary" ng-click="AddPartialView()">Add partial view</button>

Clicking that button has no effect whatsoever. If I add a console.log('Code was here.') to the AddPartialView(), it is not logged. Setting the ng-click value directly to alert('hello') has no effect either.

There are no errors of any kind visible.

Any suggestions on how to make this button work?

2
  • I think I wrote an answer to this some where else, I will dig it out Commented Aug 4, 2015 at 9:45
  • 2
    Here is some more info if you need it Commented Aug 4, 2015 at 9:48

2 Answers 2

1

In regards to your question, you are adding HTML that isn't compiled by Angular. You need to use $compile on your newly added HTML element and then bind it to a scope. The $compile() function returns a link() function which you use to bind a scope to. Example:

$compile(new-element)(scope-to-bind-to)

NOTE: You should not be manipulating the DOM via a controller. This is considered bad practice. You should be using a custom directive or some combo of Angular directives (ngIf, ngSwitch, ngInclude). I recommend watching AngularJS best practices.

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

1 Comment

Regarding DOM manipulation, this is for a limited time proof of concept that I just want to get working first. Once I proof it can be done, I get time to do it properly. I'll look into $compile.
1

I've looked into $compile, as suggested by Itamar L. and got it to work. The samples I found were using Directives as well, so I implemented them anyway:

angular.module('directives.api').directive("PartialViewLoader", [
    '$compile',
    'chainedScreensService',
    function (
        $compile,
        chainedScreensService) {
        return {
            restrict: 'A',
            scope: {
                view: '=',
                parent: '='
            },
            controller: function() {
            },
            link: function (scope, element, attrs) {

                chainedScreensService.GetPartialView(attrs.view).then(function (viewData) {
                    var linkFunc = $compile(viewData);
                    var content = linkFunc(scope);
                    element.append(content);

                    if (attrs.parent != 'undefined' && attrs.parent != undefined && attrs.parent.length > 0) {
                        chainedScreensService.CollapsePartialByIdentifier(attrs.parent);
                    }
                });
            }
        }
    }
]);

I use it like this:

<div ng-controller="collapseController">
    <div id="breadCrumbContainer" style="display: inline"></div>
    <div id="mainContainer">
        <div id="personContainer" partial-view-loader view="persoon" parent="" class="open"></div>
    </div>
</div>

That in itself displays the first page, which has a button to the next, as mentioned. The associated function, found in the collapseController, is this:

self.AddNextScreen = function (parentViewIdentifier, targetContainerId, breadCrumbContainerId) {
    self.AddChildByDirective("NextScreen", parentViewIdentifier, targetContainerId, breadCrumbContainerId);
}

The code for AddChildByDirective:

self.AddChildByDirective = function (viewIdentifier, parentViewIdentifier, targetContainerId, breadCrumbContainerId) {
    var html = '<div id="' + viewIdentifier + 'Container" fvl-partial-view-loader view="' + viewIdentifier + '" parent="' + parentViewIdentifier + '" class="open"></div>';

    var target = $('#' + targetContainerId);

    var linkFunc = $compile(html);
    var content = linkFunc($scope);
    target.append(content);

    self.UpdateScreenBreadCrumb(viewIdentifier, breadCrumbContainerId);
}

At this point I still need to test actual chaining, but this works to load a new screen and collapse the previous.

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.