Function does not run without setTimeout

Asked

Viewed 169 times

1

I’m having a problem executing a function by clicking on icheck. In case, the function is only called if I give a setTimeout 1 millisecond, less than that or without timeout the function is not executed. How can I do to execute this function without using timeout?

vm.selecionaFiltros = function(){
    $('.marcas').iCheck({
        checkboxClass: 'icheckbox_minimal',
        radioClass: 'iradio_minimal',
    });

    $timeout(function() {
        $('.marcas').on('ifChanged', function (event) {
            console.log('1');
        });
    }, 100);
}
  • Do you run all this bit every time the user clicks on the checkbox? . icheck turns the elements into icheck objects and is usually only used once, right after the page loads. Also, if it is to detect the click you should use the ifClicked or ifToggled events.

  • Hello @Eduardomoreira, I tested using ifClicked and Toggled and removed the startup icheck from within the function, but my problem persists, since the problem is not in the icheck, it is in the site render time, that can not catch the event by clicking. The function selectFilters is called after finishing ng-repeat filter listing.

  • @Bernardokowacic the function vm.selecionaFiltros is called automatically or needs to have some user interaction? Example, click on a checkbox?

  • Hello @Celsomtrindade, then, the function is called when you load the page, automatically. Currently I took the boot from inside the function, I left only the part that checks whether it was marked or not.

  • @Bernardokowacic based on this I’m going to try an answer that I imagine is the problem.. We talked more over the comments there.

1 answer

2


If that function vm.selecionaFiltros is called automatically, the possible problem is that it is happening outside the scope of the AngularJs.

What does that mean?

It means that the digest cycle has passed, so the changes will not be applied. digest cycle is a process of AngularJs (also known as Dirty checking) that makes the comparison of all bindings through the watchers ({{meuEscopo}} or ng-bind="meuEscopo" - each element of this in your view generates a new watcher) to check whether that data has changed and, if so, update the view with that new value.

If your function is executed after the digest cycle means that no matter how much the changes AngularJs still don’t "know" it.

When a digest cycle is fired?

They are always fired when the application loads or through interactions with functions of Angularjs itself, for example, ngClick, ngChange, ngBlur, etc.. Or, within a controller or directive, through the use of $timeout (which is what you’re doing) and $interval and, finally, through a manual call, explained better below.

How to solve?

The way to solve this would be to manually call the digest cycle.

There are 2 methods of obtaining the same final result:

  • $scope.$digest()
  • $scope.$apply()

Both are similar and will give you the same end result. However $scope.$apply() will trigger the event $rootScope.$digest() which affects all scopes and their elements Child as long as the $scope.$digest() affects only the local scope and its elements Child, giving you a better performance, since it will not affect the application as a whole.

Simple example, assuming in the same view as this ng-repeat you own a directive that shows the weather, it has no connection with that list and has its own scope, since it comes from a directive. If you call $scope.$digest(), the digest cycle will not check the watchers that belong to him, so you have more performance. But if you call the $scope.$apply(), how will he fire the $rootScope.$digest() instead of $scope.$digest() - that is, the global cycle, that weather Directive and all its Watchers and Child will also be validated by the cycle.

When using one or the other?

If you are sure that the called function will only affect values that are within that scope, call the $scope.$digest(). But if you know that the interaction with these functions can interfere in scopes that are outside the current one, use the $scope.$apply().

Example: Assuming this list of ng-repeat whether to select what type of temperature is displayed on directive. Celsius, Kelvin or Fahrenheit, then if I click on one of these elements of ng-repeat, I need to alter an element outside my scope, so I call the $scope.$apply().

So your code would look like this:

vm.selecionaFiltros = function(){
    $('.marcas').iCheck({
        checkboxClass: 'icheckbox_minimal',
        radioClass: 'iradio_minimal',
    });

    $('.marcas').on('ifChanged', function (event) {
        console.log('1');
        $scope.$digest(); //aqui
    });

    $scope.$digest(); //ou aqui
}

If you want, you can still remove the function declaration using the vm and use a function JS simple.

function selecionaFiltros() {
    [...]
}

//chamada da função
selecionaFiltros();

The vm in front serves to perform a function that is called through the view, with ng-click, ng-blur, etc...


Note: Just to remind you, how you’re using the syntax of vm, needs to inject the $scope before I can use it.

  • Hello @Celsomtrindade, I put the $Scope. $Digest(); within the ifChanged function and nothing happened, continued without working, tried to put in at the bottom line, but then gave error saying $Digest is not a function. I tried to add $Digest into module inject and function call and gave error as well. I am injecting $Scope to use it. The same thing happened with $apply.

  • @Bernardokowacic what you need to inject is $Scope, not $Digest or $apply. If it still doesn’t work, assemble a fiddle or plunkr where the problem can be reproduced to be analyzed better.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.