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

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.