Gustavo Hoirisch
Gustavo Hoirisch

Reputation: 1657

Use a scope variable as parameter in function and use its reference instead of value

I would like to try and have a generic function in my controller that I can use from my view to tell a specific variable within the scope to change to a specific value.

Simplified example

Controller

$scope = {
    hair: {
        color: 'blue',
        length: '2cm'
    },
    mouth: 'wide',
    arms: [
        {
            fingers: 5,
            color: 'brown'
        },
        {
            fingers: 4,
            color: 'white'
        }
    ]
}

$scope.updateVariable = function(scopeVariable, value){
    scopeVariable = value;
}

View

<a ng-click="updateVariable(hair.color, 'red');">red hair</a>
<a ng-click="updateVariable(hair.length, '5cm');">increase hair length</a>
<a ng-click="updateVariable(mouth, 'narrow');">narrow mouth</a>
<a ng-click="updateVariable(arms[0].fingers, 4);">4 fingers</a>

It seems only the value of the variable is passed on to the function but not the reference. Is there a way for me to get the reference to the scope variable instead of its value from a function parameter? Furthermore can that be done dynamically? And by this I mean I need to pass the "path" to where this variable is located in the scope.

I am aware that this can be done with independent setter functions (i.e.: setMouth('narrow')) but let's assume for the sake of this exercise we do not know ahead of time the structure of the scope in the controller but only in the view and because of that we need a generic function that can deal with property.

Upvotes: 1

Views: 95

Answers (2)

Shaun
Shaun

Reputation: 927

If you pass objects around, they will be by reference.

For instance, rather than passing hair.color back, if you sent hair back instead it would work.

So to update as well?

Set it in the click is one option .

ngclick="hair.color = 'red'"

Also you can pass properties around.

Dot notation and bracket notation with variables are the same.

So hair.color is the same as hair["color"] - the later can be dynamic. You could pass a property name and update it .

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1073968

It seems only the value of the variable is passed on to the function but not the reference.

Correct.

Is there a way for me to get the reference to the scope variable instead of it's value from a function parameter?

No, JavaScript simply does not have that (which is called pass by reference). Instead, you can pass the name of the variable and then use that name in your function:

<a ng-click="updateVariable('hair.color', 'red');">red hair</a>
<a ng-click="updateVariable('hair.length', '5cm');">increase hair length</a>
<a ng-click="updateVariable('mouth', 'narrow');">narrow mouth</a>
<a ng-click="updateVariable('arms[0].fingers', 4);">4 fingers</a>

then apply the techniques in this question and its answers to update $scope from the path. Adapting the function from the answer by Alnitak to make it a setter:

Object.setByString = function(o, s, value) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            if (i == n - 1) {
                o[k] = value;
                return value;
            }
            o = o[k];
        } else {
            return value;
        }
    }
    return value;
};

then

$scope.updateVariable = function(scopeVariablePath, value){
    Object.setByString($scope, scopeVariablePath, value);
};

Upvotes: 1

Related Questions