0

For some reason when using this function('testclickfn') as ng-click on dynamic elements, it doesn't invoke the function. Here is the angularjs file:

app.controller('testctrl',function($scope){
     testfn($scope);

     $scope.showelements = function(){
        displayTestRows();
     }
});

function testfn($scope){
   $scope.testclickfn = function(){
     alert('testing click fn');
   };
}

function displayTestRows(){
   for(var i=0; i < 5; i++){
      $("#testdiv").append('<p ng-click="testclickfn()">click me</p><br>'); 
   }
}

HTML page that calls angularjs controller 'testctrl':

<div id="testdiv" ng-controller="testctrl">
   <button ng-click="showelements()">Show dynamic elements</button><br>
</div>

I'm assuming since the 'click me' tags are being generated after angular has loaded the page, it doesn't know of anything after page is generated so ng-click="testclickfn()" doesn't get registered with angularjs.

How do I get around this situation?

4
  • 1
    Did you try to do an “ng-for” instead your “displayTestRows()”? Commented Aug 20, 2018 at 23:47
  • What if you run $scope.$apply(); right after the for? Commented Aug 20, 2018 at 23:49
  • @SamuelRoberto no because i need to know how to bind dynamically created content/directives to angularjs. Commented Aug 20, 2018 at 23:59
  • @jpacareu i placed that code in the line right after for loop, it didn't work. Commented Aug 21, 2018 at 0:00

2 Answers 2

4

You're creating elements in a way angular has no idea about (pretty bad practice), but not to worry, you can let angular know!

Change the controller signature to

controller('testctrl', function($scope, $compile) {

Then run compile the new elements manually to get the ng-click directive activated

$scope.showelements = function(){
    displayTestRows();
    $compile($("#testdiv").contents())($scope);
}

If you cant tell, having to use jquery selectors inside your controller is bad, you should be using a directive and the link function to attach the element to the scope (ie, what if you have multiple testctrl elements?), but this'll get you running

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

7 Comments

thanks. I know its bad, im new to angular and on time crunch to get some work done. So i'm cutting some corners, and learning new things as well lol. Thanks.
Im a big fan of people answering the question, not going "you shouldnt do that", just in case there's a really weird case someone needs to do this. But if not, I included a warning that there are better ways too 👍
Actually it worked. I had to change controller sign...Thanks again.
but question, how would i have done it the proper way with respect to angularjs?
Was $compile not available? Yeah, you need to ask angular to give you its API. $rootScope, $compile, $routeProvider, none of them are on the global scope (like jquery's $(), for instance). It's a good thing though, because it can give you better error messages if, for instance, you're trying to use $rootScope in a config function, or something else that just wouldnt work
|
0

As promised

The general rules are that no JS should be outside the angular functions, and that DOM manipulation, where appropriate should be handled by angular also.

Example 1: powerful

Have a look

<div ng-controller="ctrl">
  <button ng-click="show('#here')">
    create
  </button>

  <div id="here">
    I'll create the clickables here.
  </div>
</div>

use controllers for things that share stuff between a lot of different things

  .controller('ctrl', ['$scope', '$compile', function($scope, $compile) {
    $scope.sharedVariable = 'I am #';

    $scope.show = function(where) {
      where = $(where).html('');

      //lets create a new directive, and even pass it a parameter!
      for (var index = 0; index < 5; ++index)
        $('<div>', {'test':index}).appendTo(where);

      $compile(where.contents())($scope);
    };
  }])

use directives for non-unique elements that each have their own states

  .directive('test', function() {
    return {
      //these too have their own controllers in case there are things they need to share with different things -inside them-
      controller : ['$scope', function($scope) {
        $scope.test = function() {
          //see, no selectors, the scope already knows the element!
          $scope.element.text(
            //remember that parent controller? Just because we're in another one doesnt mean we lost the first!
            $scope.$parent.sharedVariable +
            $scope.index
          );
        }
      }],

      //no need to do things by hand, specify what each of these look like
      template : '<p>click me</p>',

      //the whole "angular way" thing. Basically no code should be outside angular functions.
      //"how do I reference anything in the DOM, then?"; that's what the `link` is for: give the controller access using `scope`!
      link : function(scope, element, attributes) {
        //you can assign "ng-click" here, instead of putting it in the template
        //not everything in angular has to be HTML
        scope.element = $(element).click(scope.test);
        //did you know you can accept parameters?
        scope.index = Number.parseInt(attributes.test) + 1;
      },

      //just some set up, I'll let you look them up
      replace : true,
      restrict : 'A',
      scope : {}
    };
  })

Example 2: Simple

But that is just a very generic and powerful way of doing things. It all depends on what you need to do. If this very simple example was indeed all you needed to do you can make a very simple, almost-all-html version:

<div ng-controller="ctrl">
  <button ng-click="items = [1, 2, 3, 4, 5]">
    create
  </button>

  <p ng-repeat="item in items" ng-click="test($event)">
    <span>click me</span>
    <span style="display:none">I am #{{item}}</span>
  </p>
</div>
.controller('ctrl', ['$scope', function($scope) {
  $scope.test = function($event) {
    $($event.currentTarget).children().toggle();
  };
}])

That's it, works the same almost

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.