0

I have these functions:

$scope.addProduct = function($event, obj) {

    var myEl = angular.element($event.target);

    myEl.parent().html('<button class="btn btn-danger btn-xs" ng-click="removeProduct('+ obj.id +')">Remove from Widget</button>');

};

$scope.removeProduct = function(id) {
    console.log('Remove ->' + id);

};

When I click on "addProduct" it work but when I click on "removeProduct" does not work. Looks like it doesn't listen the click on the new button that I added. How can I solve it?

4
  • 4
    adding html the jquery way won't make angular bindings work. You'll have to re-think your whole code and code it more angular-friendly with a directive/template. please provide a jsfiddle to help you more. Commented Jun 5, 2014 at 8:05
  • I think you have completely right! I'll create a directive for that, it's the best solution. Thanks man. Commented Jun 5, 2014 at 8:11
  • 1
    by the way, I think the todo tutorial of angularjs.org homepage would really help you :p : jsfiddle.net/api/post/library/pure Commented Jun 5, 2014 at 8:15
  • Maybe you don't even need a directive. Have both buttons in your template and play with their visibility (ng-show or ng-if). Have a boolean variable like $scope.viewState.productAdded to control which button is visible. Commented Jun 5, 2014 at 8:17

3 Answers 3

1

In order for ngClick to take effect, you need to first compile your HTML and link it to the $scope:

.controller('someCtrl', function ($compile, $scope) {
    ...

    $scope.addProduct = function($event, obj) {
        var myEl = angular.element($event.target);
        var myBtn = $compile('<button class="btn btn-danger btn-xs" ng-click="removeProduct('+ obj.id +')">Remove from Widget</button>')($scope);
        myEl.after(myBtn);
    };

    $scope.removeProduct = function(id) {
        console.log('Remove ->' + id);
    };
});

UPDATE:

Kos Prov's comment is very true - sometimes you think about solving the problem, but you don't think the question was wrong in the first place.

So, of course manipulating the DOM should be a directive's responsibility, so I created a directive to do what you want (according to your question):

app.directive('removableProduct', function ($compile) { var btnTmpl = '' + 'Remove from Widget' + '';

    return {
        restrict: 'A',
        scope: {item: '='},
        template: '<div ng-click="addProduct($event)">{{item.description}}</div>',
        controller: function ($scope) {
            $scope.addProduct = function (evt) {
                var myEl = angular.element(evt.target);
                var myBtn = $compile(btnTmpl)($scope);
                myEl.after(myBtn);
            };
            $scope.removeProduct = function(id) {
                console.log('Remove -> ' + id);
            };
        }
    };
});

See, also, this short demo.

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

4 Comments

This fixes the problem but it's like the worst possible Angular code that could ever exist. Promoting ugly quick fixes is not good for the community.
@KosProv: My excuses to the community :) I updated my answer. Thx for the heads-up - I hope the damage done to the community was not permanent :P
Fear not my friend. The protector of the community is here (that's me, yeah :P). Now, seriously: the class of "I come from jQuery, the natural thing to do is this, why doesn't it work?" errors are increasing. I even saw a completed project that all controllers where like $scope.$on('$viewContentLoaded', function() { /* jQuery DOM manipulation here */}). Personally, I prefer to comment that this is bad design than trying to fix it. I removed my downvote and my apologies if I was a bit harse.
I know exactly what you mean :) Sometimes I focus on solving the "problem" that I don't see the actual problem (although looking back I feel bad for letting something so obviously non-Angularish slip through). Thank you for watching over us :P
0

You have a problem which should not exist if you do it in Angular way.

For every product try to hold a boolean value like 'productAdded' in your $scope model.

Then you can do in example:

<div ng-repeat="product in products">
    <button ng-show="product.productAdded" class="btn btn-danger btn-xs" ng-click="addProduct(product)">Add to Widget</button>
    <button ng-show="!product.productAdded" class="btn btn-danger btn-xs" ng-click="removeProduct(product.id)">Remove from Widget</button>
</div>

Hope this clarifies a bit for you!

Comments

0

If you want to add a remove button after a product is added, you should add the remove button within the ng-repeat itself:

JS

<div ng-app="app" ng-controller="ctrl">
   <ul>
      <li ng-repeat="product in products">
           {{product.name }}<button ng-click="deleteProduct(product)">Delete</button>
      </li>
   </ul>
</div>

Controller

var app = angular.module('app', []);
app.controller('ctrl', function($scope) {
    $scope.products = [{ name:'pencil' }, { name: 'crayon' }, { name: 'pen' }];
    $scope.deleteProduct = function(product) {
        var index = $scope.products.indexOf(product);
        if (index >=0) {
            // remove the product
            $scope.products.splice(index, 1);
        }
    }
});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.