1

I want to bind angular event and model to an html element appended by javascript code.

My code is here. https://jsfiddle.net/hq7qk48n/13/

<div ng-app>
    <div ng-controller="MyController">
        <input type="text" ng-model="text1">
        <a href="#" ng-click="onClick()">click1</a>

        <div id="append"></div>
        <p ng-if="clickedTime1">click1 : {{ clickedTime1.toLocaleString() }}</p>
        <p ng-if="clickedTime2">click2 : {{ clickedTime2.toLocaleString() }}</p>
        <p>{{ text1 }}</p>
        <p>{{ text2 }}</p>
    </div>
</div>


function MyController($scope) {
    $scope.clickedTime1 = null;
    $scope.clickedTime2 = null;

    $scope.onClick = function () {
        var html = '<input type="text" ng-model="text2" name="text"> <a href="#" ng-click="onClick2()">click2</a>';
        $("#append").empty();
        $("#append").append(html);
        $scope.clickedTime1 = new Date();
    }

    $scope.onClick2 = function () {
        $scope.clickedTime2 = new Date();
    };
}

onClick2() doesn't work. and model "text2" is not updated. How to bind onClick2 function and text2 model?

Need to compile an html element? How?

yng13
  • 13
  • 1
  • 3
  • holy moly..you should perhaps seek an `angularjs` only solution instead of trying to mix and match and hack something together.. also read up on directives like `ng-show ng-hide` and try to avoid DOM manipulations in the Controller. Here is an SO post which is a good read: [thinking-in-angularjs-if-i-have-a-jquery-background](http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background) – Shehryar Abbasi May 23 '15 at 01:08
  • if you want to add `dynamic HTML` content, then it needs to be linked back to a `scope` again -- read this on the `$compile` directive: [angularjs docs](https://docs.angularjs.org/api/ng/service/$compile) and then see some of these implementations on SO: [example1](http://stackoverflow.com/questions/24316497/compiling-dynamic-content-angularjs), [example2](http://stackoverflow.com/questions/24316497/compiling-dynamic-content-angularjs), and here's an [external blog post example3](http://odetocode.com/blogs/scott/archive/2014/05/07/using-compile-in-angular.aspx) GL!! – Shehryar Abbasi May 23 '15 at 03:44
  • You shouldn't be using jQuery and you shouldn't be doing DOM manipulation from inside a controller. This is what directives are for. The solution would be to create a directive that appends whatever DOM element you need. – tpie May 23 '15 at 04:38

1 Answers1

5

This is a little tricky because you have an ng-click in your new element. There are 2 things we need to deal with.

  1. Correctly add the element
  2. Make your new element see the scope

First we will start with your call to the method from your element. You will need to add $event to the call

    <a href="#" ng-click="onClick($event)">click1</a>

The $event object will give you information about the calling element.

You also need to add it to your method

    $scope.onClick=function($event){

Next, your element required use of the scope so we need to turn it into an element. Otherwise just html would be fine.

    var el=angular.element('<input type="text" ng-model="text2" name="text"> <a href="#" ng-click="onClick2()"/>click2</a>');

Now you can use a little jquery but exactly on the target element the way angular would do it.

    $($event.currentTarget).empty();
    $($event.currentTarget).append(el);

At this point you would see your changes but the bindings will not work because it is not attached to the scope so we need to compile it. You will need to add the $compile server to your controller

    function MyController($scope,$compile) {

Now we can use the service to compile the new element

    $compile(el)($scope);

You should now see everything functioning the way you would expect

    function MyController($scope,$compile) {
$scope.clickedTime1 = null;
$scope.clickedTime2 = null;

$scope.onClick = function ($event) {
    var el = angular.element('<input type="text" ng-model="text2" name="text"> <a href="#" ng-click="onClick2()">click2</a>');
    $($event.currentTarget).empty();
    $($event.currentTarget).append(el);
    $compile(el)($scope);
    $scope.clickedTime1 = new Date();
}

$scope.onClick2 = function () {
    $scope.clickedTime2 = new Date();
};

}

and don't forget to add the $event to your call as well.

I did not use your exact code but I tested this as I answered to verify and it worked perfectly. It might not be best practice to work with the DOM elements in your controller but sometimes it just works. That is how you do it.

Jim Fallin
  • 236
  • 1
  • 6