Angular
How to access $scope from an outside function
Gravatar is a globally recognized avatar based on your email address. How to access $scope from an outside function
  Carl Chambers
  All
  Jan 30, 2018 @ 06:35pm

Angular v1.5.0
I have a Bootstrap Popover that contains HTML content.
That Popover's HTML content includes a button which, when clicked, needs to have access to the $scope but I have not been able to figure out how to do that.

<a href="" class="js-popover"
           title="Blocks of Lookups"
           tabindex="-1"
           data-container="body" data-toggle="popover" data-placement="bottom"
           data-original-title="" data-trigger="click" data-html="true"
           data-content="<p>This setting has been updated.</p>
                         <b>This Usage Period:</b> {{ selectedSubscription.quantity }}<br/>
                         <b>Next Usage Period:</b> {{ selectedSubscription.next_quantity }}<br/>
                         <center>
                           <button class='btn btn-red' style='margin-top: 10px;' onClick='cancelQtyChange();'>
                             Cancel this Update
                           </button>
                         </center>"
            ng-show="selectedSubscription.quantity!=selectedSubscription.next_quantity">
  <i class="fa fa-warning text-red"></i>
</a>

In this line <button class='btn btn-red' style='margin-top: 10px;' onClick='cancelQtyChange();'>...
ng-click will not work. I presume that's because this HTML string is not actually part of the DOM when the page loads.
onClick() does work but I can't figure out how to access the $scope variables.

Can this be done? Or is there a better way of doing this? Any ideas appreciated.

Carl

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Harvey Mushman
  Carl Chambers
  Jan 31, 2018 @ 06:20am

try ng-click="..." onClick is a JavaScript function and will call back to the DOM looking for a function. if you want to get AngularJS to function you need to use their syntax. Here is a link to the ngClick directive.

AngularJS Documentation :: ngClick

BTW - this will cause an error if the method you are specifing in the ng-click directive does not exist in your AngularJS code. You need to have correctly defined a controller for the html page and in that controller you need to have a function statement something like:

$scope.cancelQtyChange = function(){ ...your code...}

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Carl Chambers
  Harvey Mushman
  Jan 31, 2018 @ 08:01am

Hi Harvey,

As I mentioned in the OP, ng-click does not work.
I think that the HTML elements in "data-content" are not actually in the DOM until the popover is activated and I'm guessing that's why Angular does not respond to ng-click in that HTML.

It looks like I need to either...

  1. find a way to make Angular know about the HTML elements in the "data-content".
    or
  2. find a way to get access to the $scope from outside the controller.

I've found little bits here and there that make me think (b) is possible but I don't have a solution yet.

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Rick Strahl
  Carl Chambers
  Jan 31, 2018 @ 01:48pm

This should work as long as the popover lives within the context of the ng- component you're calling. If the popover sits outside of the Angular block it won't participate in Angular binding.

Ideally you embed the popover into the main content and then this should just work or else add it as a separate 'controller' or component to dynamically load it - if it gets loaded through Angular it'll know to hook up the bindings.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Carl Chambers
  Rick Strahl
  Jan 31, 2018 @ 04:14pm

Hi Rick,

If you look at the code I posted, you'll see a couple $scope variables contained in the HTML data-content (example: {{ selectedSubscription.quantity }} ) and they display correctly.

If I change the code for the button to this (using onClick)...
<button class='btn btn-red' style='margin-top: 10px;' onClick='alert( {{ selectedSubscription.next_quantity }} );'>
the alert is displayed with the correct value.

If I change the code for the button to this (using ng-click)...
<button class='btn btn-red' style='margin-top: 10px;' ng-click='alert( {{ selectedSubscription.next_quantity }} );'>
nothing happens. The alert is not displayed.

So the Angular bindings in the popover data-content work fine. The ng-click does not.

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Carl Chambers
  Carl Chambers
  Feb 1, 2018 @ 11:34am

For anyone curious, I found a solution.
http://jsfiddle.net/austinnoronha/nukRe/light/

Here's the HTML for the popover.

<a href="" id="quantity-popover"
           class="js-popover"
           title="Blocks of Lookups"
           tabindex="-1"
           data-container="body" data-toggle="popover" data-placement="bottom"
           data-original-title="" data-trigger="click" data-html="true"
           data-content="<p>This setting has been updated.</p>
            <b>This Usage Period:</b> {{ selectedSubscription.quantity }}<br/>
            <b>Next Usage Period:</b> {{ selectedSubscription.next_quantity }}<br/>
            <center>
              <button class='btn btn-red' style='margin-top: 10px;' 
                      data-subscription-attribute='quantity'
                      onClick='cancelUpdate(this);'>
                Cancel this Update
              </button>
            </center>"
           ng-show="selectedSubscription.quantity!=selectedSubscription.next_quantity">
  <i class="fa fa-warning text-red"></i>
</a>

The onClick() event of the <button> contained in the popover's data-content calls the following non-Angular function.

<script>
  function cancelUpdate(oElement) {
    var attribute = oElement.getAttribute("data-subscription-attribute");
    var scope = angular.element(document.getElementById("ngCntlContainer")).scope();
    scope.$apply(function () {
       scope.cancelUpdate(attribute);
    });
  };
</script>

"ngCntlContainer" is the <div> that has the ng-controller directive.
This function then calls the function $scope.cancelUpdate() in the Angular controller.

$scope.cancelUpdate() is able to pass bound values to the web server. I have not yet worked on handling the response but I see no reason for there to be a problem.

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Rick Strahl
  Carl Chambers
  Feb 1, 2018 @ 03:47pm

Yeah this sort of stuff was a problem in Angular 1. In 2 the DOM tree is monitored directly so if you inject code into the DOM the bindings are automatically updated and represent the new state immediately without this. $scope.apply() was the bane of doing stuff in AngularJs...

It is an edge case though and probably you should think about a different design for that either way. I used to handle this by putting the dialog inline with the 'controller' and not dynamically injecting the HTML which is not really necessary most of the time with a tool like angular. And if you do keep it external then you can use emit() messages to communicate between multiple controllers.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to access $scope from an outside function
  Carl Chambers
  Rick Strahl
  Feb 1, 2018 @ 09:35pm

Thanks for your thoughts, Rick.

For now, I'm just happy to get it to do what I want it to do.

© 1996-2024