0

I have a fairly large Angular app with 15 directives and 5 services. The problem I'm having is related to updating the local scope from within a service. And with updating I mean replacing the array the scope is pointing at to another array.

The process is the following after I click an element:

clickDirective () {
    restrict: 'A'.
    link: function (scope, element, attrs) {
        if ($rootScope.hasCertainValue) {
            FirstService.handle(scope, valueX)
        }
    }
}

/* Calls FirstService.handle */

FirstService () {
    handle (scope, valueX) {
        if (certainCriteriaMet) {
            SecondService.handle(scope, valueX)
        }
    }
}

/* Calls SecondService.handle */

SecondService () {
    handle (scope, valueX) {
        /* This is the funny part*/
        console.log(scope.value) // let's assume prints: ['a']
        // Option a)
        scope.value = ['a', 'b'] // this is what I want to do
        // Option b)
        scope.value.push('b')    // this is what works

        scope.$apply()

        // Now if we ran option a) the UI is not updated
        console.log(scope.value) // prints ['a', 'b'] however
        // But when this function is called the next time
        // the value of scope.value has switched back to ['a'].

        // If we ran option b) instead, the UI is updated
        console.log(scope.value) // prints ['a', 'b'] as expected
        // The difference is that the value of scope.value is
        // still ['a', 'b'] the next time this function is called.
    }
}

So the question here is that why can't I change the object the scope is pointing at? But I can modify it instead?

The SecondService contains another function called by another directive, using the same scope. And in that function I can perform the operation I want - which is replacing the current array with a new one.

The only reasons I can think of are some sort of race conditions.

----- Edit -----

I think I'm starting to catch the problem here. The scope object I have in the SecondService is only a pointer to the real scope object.

scope.value ------> [array]
scope.atSecondService --------> scope.value -------> [array]

So when I change the array at scope.atSecondService this is what I get:

scope.value ------> [array]
scope.atSecondService -----> [newArray] <---/--- scope.value

This still makes me wonder, though, that why can I call a similar function from another directive where this works?

----- Edit 2 -----

Or maybe I'm wrong. The behavior is not consistent. It seems like I get a new local level scope created at the element level instead of accessing the $scope at the controller. However, the first time I receive the scope it's the controller's scope - that's confirmed from its value.

Maybe someone else knows better?

1 Answer 1

2
        console.log(scope.value) // let's assume prints: ['a']
        // Option a)
        scope.value = ['a', 'b'] // this is what I want to do
        // Option b)
        scope.value.push('b')    // this is what works
  • option a) you're replacing the reference with a new one, means the reference of the original scope.value is lost and replaced with a new one.

  • option b) you're only updating the array, and that is the
    expected behaviour.

If you want to clean the array and replace all the content preserving the reference you should try this:

scope.value.length = 0; //remove all the elements
[].push.apply(scope.value, ['a', 'b']); //push new values
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! This is exactly how it is!

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.