49

HTML

<table data-ng-table="tableParams" class="table table-bordered table-hover " style="border-collapse:collapse" data-ng-init="host.editSave = false" >
    <tr id="newTransaction">
    </tr>
    <tr data-ng-repeat="host in hosts|filter:search:strict" >
       <td class="hostTableCols" data-ng-hide="host.editSave">{{host.hostCd}}</td>
       <td class="hostTableCols" data-ng-hide="host.editSave">{{host.hostName}}</td>
    </tr>
</table>

Jquery

$('#newTransaction').append(
 '<td contenteditable><input type="text" class="editBox" value=""/></td>'+ 
 '<td contenteditable><input type="text" class="editBox" value=""/></td>'+
 '<td>'+
    '<span>'+
        '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'+
    '</span>'+
 '</td>'
);

Angular Script

$scope.create = function() {
       alert("Hi");
    };

Here the function called in the controller part of the AngularJS is not getting trigger from the ng-click event. The Html is getting appended successfully, but the ng-click is not working. Tell me solutions to make it work

3
  • 1
    you need to compile the new dom elements for angularjs to work... are you doing this manipulation in a directive/controller where you have access to the scope Commented Oct 9, 2013 at 9:26
  • @ArunPJohny: Am calling that function from controller. But where should I place the Compile function?? In a directive?? Commented Oct 9, 2013 at 9:38
  • I don't know about the exact scenario, but you can do something similar using ng-include and templates. Commented Oct 9, 2013 at 9:43

5 Answers 5

50

Not a perfect fix, still!!! - just to show how dynamic compilation can be done

app.controller('AppController', function ($scope, $compile) {

    var $el = $('<td contenteditable><input type="text" class="editBox" value=""/></td>' +
        '<td contenteditable><input type="text" class="editBox" value=""/></td>' +
        '<td>' +
        '<span>' +
        '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>' +
        '</span>' +
        '</td>').appendTo('#newTransaction');
    $compile($el)($scope);

    $scope.create = function(){
        console.log('clicked')
    }
})

Demo: Fiddle

Don't use controller for dom manipulation - it has to be done with the help of directives

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

5 Comments

I tried this method already and didnt know about $compile... So tried it from jquery
@MaximShoustin: Y shouldn't we use DOM manipulation from controller?? Any reasons?
@KiranKumar Usability, code clearness, maintenance. The controller should be concerned with business logic, not interface manipulation.
How to achieve the same if you are adding HTML via service where $scope is not available?
@trainoasis you can try to use the parent elements scope like $('#newTransaction').scope() ie $compile($el)($('#newTransaction').scope());
36

To make ng-click to work we need to compile this source by using $compile service. Angular should know about new generated HTML and therefore this HTML should be included to digest cycle in order to trigger ng-click and other events.

See Fiddle

Create "compilator":

.directive( 'compileData', function ( $compile ) {
  return {
    scope: true,
    link: function ( scope, element, attrs ) {

      var elmnt;

      attrs.$observe( 'template', function ( myTemplate ) {
        if ( angular.isDefined( myTemplate ) ) {
          // compile the provided template against the current scope
          elmnt = $compile( myTemplate )( scope );

            element.html(""); // dummy "clear"

          element.append( elmnt );
        }
      });
    }
  };
});

after, create dummy factory that simulates your append:

.factory( 'tempService', function () {
  return function () { 
    return '<td contenteditable><input type="text" class="editBox" value=""/></td>'+ 
            '<td contenteditable><input type="text" class="editBox" value=""/></td>'+
             '<td>'+
                '<span>'+
         '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'+
              '</span>'+
            '</td>';
  };
});

And finally call it like:

<div compile-data template="{{mainPage}}"></div> 

in Controller:

$scope.newTransaction= tempService();

For your example should be something like:

<table data-ng-table="tableParams" class="table table-bordered table-hover " style="border-collapse:collapse" data-ng-init="host.editSave = false" >
    <tr compile-data template="{{newTransaction}}">
    </tr>
    <tr data-ng-repeat="host in hosts|filter:search:strict" >
       <td class="hostTableCols" data-ng-hide="host.editSave">{{host.hostCd}}</td>
       <td class="hostTableCols" data-ng-hide="host.editSave">{{host.hostName}}</td>
    </tr>
</table>

BTW, for now you can use the same directive over your code and compile any dynamic HTML.

7 Comments

Should I implement appending the html from directive rather than doing it by jquery?
As I showed in my example use Service and add in controller $scope.newTransaction= tempService();
@KiranKumar added Fiddle to allow you to loop up how it works
Just share my case, I use Handlebar to load template for table since ng-repeat is slow when data become heavier. I apply @Maxim Shoustin solution with $compile( handleCompiledContent )( scope ); before attach it to the DOM, then I insert it with jQuery. It work on-the-fly. But one thing to point out, the this in handlebar for ng-click will not work if it is rendered under an object or array loop. It refer to the object/array variable instead in handlebar.
What if I can' have predefined div with the given compile-data directive, because the service creates it? And also can't compile via $scope inside the service ... I would insert div with compile-data directive, but who would compile that first to recognize the directive ... same problem for me then?
|
25

you can use angular.element(this).scope() without use of ng-click

and change

'<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'

To

'<button id="createHost" class="btn btn-mini btn-success" onclick="angular.element(this).scope().create()"><b>Create</b></button>' is good

6 Comments

can we do this without scope.. I've declared my Popup Template while creating popup in factory.
How to send parameters init ?
@Sana angular.element(this).scope().init(1,'false'); so simple
I am using this but it says Video is not defined. Any idea return '<input type="radio" name ="VideoRadioButton" onclick="angular.element(this).scope().productChange('+data.ID+',"Video" )" />';
You cannot pass ng-repeat iterating item as a parameter to the function.
|
3

I needed to have Cordova open the dynamic link in a new window, so my solution was to put the ng-click on the parent element and look at the event.target to see what was clicked on:

<p ng-bind-html="foo.barhtml" ng-click="generalClick($event)"></p>

then

.controller('FooCtrl', function ($scope) {
    var html = '<a href="http://www.google.com">google.com</a>';

    $scope.foo.barhtml = html.replace(/href/g, 'data-href');

    $scope.generalClick = function(event){
        // have Cordova open the link in a browser window
        window.open(event.target.attributes['data-href'].value, '_system');
    }
})

Comments

2

you need to add $compile service here, that will bind the angular directives like ng-click to your controller scope.Something like:

var divTemplate = '..your div template';
var temp = $compile(divTemplate)($scope); 

Then append it to the HTML:

angular.element(document.getElementById('foo')).append(temp);

You can also bind the event to the div as following:

var div = angular.element("divID");
div.bind('click', $scope.addPhoto());

1 Comment

Won't work if you are adding the HTML inside the service for some reason.

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.