0

I have a one-page site that I am building out and this is my first time using Angular on a site. Building it on top of Laravel too for the backend but that is beyond the scope of this question.

I need to be able to open a modal on a main page view which will add a new resource (e.g. a new client) or edit a resource. I want to somehow get the form's html inside the modal body when the $uibModal.open()'s controller is called and set the $scope.modalBody equal to the injected items.modalBody (the only way this works is if I use:

$scope.modalBody = $sce.trustAsHtml(items.modalBody);

The only problem now is that anything inside the HTML body, Angular will not use it's magic and do any data-binding. It is still in the raw form of

{{ object.property }} or since I'm using Laravel and avoiding conflict with the Blade template engine:

<% object.property %>

See screenshot: screenshot

I have been banging my head against the wall on this one...I have tried putting $scope.$apply() in my directive and my controller, neither of which worked. I have a feeling that is the source of my problem though. I have also tried making the html just a <new-client></new-client> directive and using templateUrl: 'views/clients/add.php' which would be ideal, but the template is not being included inside the <new-client></new-client>.

I'm using ui-bootstrap 0.14.3 and Angular 1.4.8.

Could this be a bug? Or am I doing something wrong? Anyone have a better way of getting a form into my modal? Let me know what code you want to see so I don't clutter this post with unnecessary code blocks.

1 Answer 1

1

I have come across a similar issue with using jQuery's AJAX to receive template strings and append it to a server.

So when HTML is added via jQuery, bound html string, etc., angular doesn't know it needs to automagically compile this data.

What you need to do is use the $compile service, to $compile your html and then attach the correct $scope to it:

`$compile('jQuerySelectorReturningHtmlOrAnHTMLStringThatNeedsToBeCompiled')($scope);`

There are multiple examples in Angulars Documentation for $compile that can give you an idea of what is happening. I think by what you have described the same thing is happening here in your situation.

The key is to call this $compile service function after the html has been bound to the page.

EDIT:

There are a few other options based on some comments, that will serve as a viable solution to rendering this content on your view. For example a directive that takes a string attribute representing the HTML string of your desired view.

1. Modify your directive template in the compile step:

You have the ability to modify your template before the directive compiles and binds any attributes to it, to that directives scope:

app.directive('myAwesomeCompileStepDirective', [myAwesomeCompileStepDirectivef]);

function myAwesomeCompileStepDirectiveFn() {
  return {
    restrict: 'EA',
    compile: function compileFn(tAttrs, tElement) {
      //Here you can access the attrs that are passed into your directive (aka html string)
      tElement.html(tAttrs['stringThatYouWantToReplaceElementWith']);

      return function linkFn(scope, element, attrs, controller, transcludeFn) {
        //if all you want to do is update the template you really don't have to do anything
        //here but I leave it defined anyways.
      }
    }
  }
}

You can view a file I wrote for a npm component which uses this method to modify my directive template before it is compiled on the page & you can also view the codepen for the complete component to see it in action.

2. Use $compile service to call $compile in link function using directive attrs.

In the same way as the aforementioned method, you can instead inject the $compile service, and call the function mentioned above. This provides a bit more work, for you but more flexibility to listen to events and perform scope based functions which is not available in the compile function in option 1.

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

4 Comments

This definitely sounds like a solution that is along the lines of what I'm thinking. So will $compile($sce.trustAsHtml(items.modalBody)) return a "compiled" version of the HTML string? Or would I need to apply it to the $scope.modalBody property once initialized?
Yes it will. It is common to see in directives that the element variable provided in the link function, is assigned to the returned value of a $compile fn. Just make sure that you attach the appropriate scope as the second argument as an IIEF.
You're probably needing something like this: elem.html( templateString ); then you compile it like so $compile( elem.contents())( $scope ). This is being done in the link function on the directive BTW
Ok so I have added a plnkr for you guys to look at plnkr.co/edit/wtWqUkBpRo1BoCV2UH0I?p=preview hopefully you see what I do. It uses the values of modalTitle and modalBody but the directive <new-client></new-client> is not being "sensed" (not sure what word you would use to describe that behavior).

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.