user1893354
user1893354

Reputation: 5938

Angular ng-click function requiring two clicks to take effect

I have the following directive

app.directive('replybox', function ($timeout, $window, $compile, $sce) {
    var linkFn = function (scope, element, attrs) {


        var exampleText= element.find('p');
        var btn = element.find('button');

        var windowSelection="";

        scope.okOrCancel="None";

        exampleText.bind("mouseup", function () {
            scope.sel = window.getSelection().toString();
            windowSelection=window.getSelection().getRangeAt(0);
            if(scope.sel.length>0) {      
                scope.showModal = true;
                scope.$apply();
            }
        });


        btn.bind("click", function () {

            if(scope.okOrCancel=='ok'){
                range = windowSelection;
                var replaceText = range.toString();
                range.deleteContents();
                var div = document.createElement("div");
                div.innerHTML = '<poper><a href=""  popover-trigger="mouseenter" uib-popover="'+scope.selection+'">' + replaceText + '</a><button type="button" class="btn btn-danger btn-xs">&times;</button></poper>';
                var frag = document.createDocumentFragment(), child;
                while ((child = div.firstChild)) {
                    frag.appendChild(child);
                }
                $compile(frag)(scope);
                range.insertNode(frag);
                scope.showModal=false;
            } 

            if(scope.okOrCancel=='cancel'){
                scope.showModal=false;
            }

            scope.selection="None";
            scope.okOrCancel='None';
        });



    };
    return {
        link: linkFn,
        restrict: 'A',
        scope: {
            entities: '=',
            selection:'='
        },

        template: `<ng-transclude></ng-transclude>
                    <div class="modal fade in" style="display: block;" role="dialog" ng-show="showModal"> 
                        <div class="modal-dialog"> 
                            <div class="modal-content">
                                <div class="modal-body">
                                    {{sel}}
                                </div>  
                                <div class="radio">
                                    <div ng-repeat="x in entities">
                                        <div class="radio">
                                            <label>
                                                <input type="radio" name="choice" ng-model="$parent.selection" ng-value = "x">
                                                    {{x}} 
                                            </label>
                                        </div>
                                    </div>
                                </div>   
                                <div class="modal-footer"> 
                                    <button type="button" class="btn btn-primary" ng-click="okOrCancel='ok'">
                                        Ok
                                    </button> 
                                    <button type="button" class="btn btn-primary" ng-click="okOrCancel='cancel'">
                                        Cancel
                                    </button> 
                                </div> 
                            </div> 
                        </div> 
                    </div>`,
        transclude: true
    };
});

So there is a modal in the template which contains an "Ok" and a "Cancel" button. There is an ng-click on these buttons which sets scope.okOrCancel to the appropriate value. btn binds to a button click and performs different actions depending on the state of scope.okOrCancel. When the "Ok" button is clicked everything works as expected. But the "Cancel" button requires two clicks in order for the modal to dissappear. I would think this would happen immediately within

if(scope.okOrCancel=='cancel'){
      scope.showModal=false;
}

Can anyone tell me why the cancel button requires two clicks to close the modal?

Upvotes: 1

Views: 1866

Answers (2)

Varit J Patel
Varit J Patel

Reputation: 3520

Currently you have a mix of jQuery and angularjs for your ok and cancel click. Probably that is the reason to require two clicks to take effect.

If I were you, I would have write click like below:

Template:

<div class="modal-footer"> 
    <button type="button" class="btn btn-primary" ng-click="okClick()"> Ok </button>
    <button type="button" class="btn btn-primary" ng-click="cancelClick()"> Cancel </button>
</div>

In JS:

scope.okClick = function() {
    range = windowSelection;
    var replaceText = range.toString();
    range.deleteContents();
    var div = document.createElement("div");
    div.innerHTML = '<poper><a href=""  popover-trigger="mouseenter" uib-popover="'+scope.selection+'">' + replaceText + '</a><button type="button" class="btn btn-danger btn-xs">&times;</button></poper>';
    var frag = document.createDocumentFragment(), child;
        while ((child = div.firstChild)) {
            frag.appendChild(child);
        }
    $compile(frag)(scope);
    range.insertNode(frag);
    scope.showModal=false;
} 

scope.cancelClick = function() {
    scope.showModal=false;
}

scope.selection="None";
scope.okOrCancel='None';

I hope this helps you!

Cheers

Upvotes: 2

Alexander Leonov
Alexander Leonov

Reputation: 4794

Completely agree with varit05's answer. Most likely it's because you do not trigger digest cycle in the click event handler. But in any way, the point is: it's not very good idea to mix jquery and angular stuff, unless: a) you absolutely sure it's necessary; b) you understand very well what you're doing and why; otherwise it will lead to such an unexpected consequences.

Just another a small addition. Another problem is here:

$compile(frag)(scope);
range.insertNode(frag);

The correct approach would actually be to insert new nodes into real DOM and only then $compile() them. Otherwise, any directives with require: "^something" in the DOM being inserted will fail to compile because they would not be able to find necessary controllers in upper nodes until new nodes actually make it to the "main" DOM tree. Of course, if you absolutely sure you don't have that then you can leave it as is and it will work... But then the problem will just wait out there for its "finest hour".

Upvotes: 1

Related Questions