1

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.

2 Answers 2

1

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);
};
Sign up to request clarification or add additional context in comments.

1 Comment

This is so similar to my attempt! Thanks for leading me to this solution, it does exactly what I was after!
1

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 .

5 Comments

The notion that objects are passed around as reference is good to know however your answer still assumes some knowledge of the scope structure in the controller. On the other hand assigning it in theng-click handler makes me lose the ability to delay this assignment or defer it to another function which is really what I am trying to do.
You asked about object references in your question. End of story is pass an object. You were the one that bound the view with hard coded attributes. You also shouldn't assign to $scope like you are. You set on it, like $scope.blah you don't redefine $scope = {} - which is probably half your problem.
No need to get agressive here buddy. You can clearly see it says "SIMPLIFIED EXAMPLE". I am pretty sure I got the idea across since the other answer that was not yours was spot on.
Not being aggressive at all, apologies if it came across that way. I only responded as the other answer is misleading IMO implying reference types aren't in Javascript. Doesn't change the fact you're assigning scope incorrectly, and passing strings around to represent underlying objects is an anti-pattern.
I appreciate that and I definitely recognize the beauty of passing objects around like I mentioned in my first comment. I am not so sure about the anti pattern however as I can't change the structure coming from the backend so the fact that stand for me is to Just get it to work(^tm).

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.