Setting dynamic ng-model names in AngularJS
Asked Answered
C

2

13

There are similar questions here and here, although my use-case is a little different.

I have an object called uniqueLists which looks like this:

$scope.uniqueLists - {
    name: [
            'string1',
            'string2',
            'string3'
            // Lots of strings
    ],
    Category: [
            'string1',
            'string2',
            'string3'
            // Lots of strings
    ],
    designer: [
            'string1',
            'string2',
            'string3'
            // Lots of strings
    ]
}

I'm trying to build a search function out of this list. Currently, I can display all the list items in checkboxes on the page like this (the following code uses Jade templating engine for Node/ExpressJS, it's easy enough to understand even if you're not familiar with it. Indent == child node of the line above it)

div(class="searchNav")
    p(ng-repeat="param in searchParams") {{param[0] + ' = ' + param[1]}}

    div.row-fluid(ng-repeat="(key,val) in uniqueLists")
        form(ng-model="???") {{key}}
            label.checkbox(ng-repeat="value in val")
                input(type="checkbox", ng-model="?????") 
                {{value}}

The only part I'm having issues with is the ng-model of my form and checkboxes. I want the form's ng-model == {{key}}. I've tried setting that but it breaks Angular. I've also tried ng-model='uniqueLists[index][0]' but, again, Angular doesn't parse this and just makes every form's model the string uniqueLists[index][0].

Same deal with the input checkboxes, I want their ng-model="{{value}}". Is there a way to do this in my controller perhaps? I can't think of anything that will work inside of ng-repeat.

A small note to anyone who stumbles on this question

As you'll see in the answer/fiddle below, when you refer to object/positions in an ng-model they aren't rendered into their correct names in the DOM, but they seem to work with Angular as though they are.

For instance, in the above code, setting ng-model="uniqueLists[key][val]" renders in the DOM as ng-model="uniqueLists[key][val]", but behaves as though it's ng-model="uniqueLists[name][string1]".

Seems to be a bizarre quirk of Angular, this tripped me up because I was checking the ng-model names in my browser before hooking it up to my controller, and when I saw it wasn't parsing the object for the correct values I assumed it wasn't working.

Cantor answered 28/7, 2013 at 3:43 Comment(3)
Hello, just two little questions. The first, about the form+ng-model, I don't really understand why a ng-model here, wouldn't it be easier with a simple 'name' attribute ? And the second one, in the sample uniqueLists you provided, some values are duplicated (which I think will also be the case in you real data), if you do something like 'ng-model="value"', with your example, you will only have 3 models, and the checkboxes will be linked across categories, plus, if you display the {{value}} next to them, it will be replaced by true/false at the first click, so what do you really want to get ?Tourniquet
The sample I gave was just placeholder, the values in there are all unique (hence the name uniqueLists!). These are checkboxes, and I want each to have an ng-model name that refers to the text in the checkbox's label. This is because it's part of a search, I have the search parameters in my controller and I want the checkboxes that they pertain to to be 'checked'. Make sense? Like if you search for "Hello", "Test1" and "Test2", on the results page the checkboxes with those strings would be checked.Cantor
possible duplicate of How can I set a dynamic model name in AngularJS?Cuesta
T
10

I'm still not totally sure I understood all your problem, but I'll still give you this code : http://jsfiddle.net/DotDotDot/7AU6A/1/

To explain a bit, I used a slightly modified data sample (in order to have unique strings), and instead of creating a model simply equal to a defined {{value}} I've put all the models in an object, so you can easily go to object[key][value] (in your case it would be something like object['name']['string1']) and I associated those values to the checkboxes. The only thing I had to do is to create it from the data sample object, so it forces the controller to parse all the data once.

It's quite siple when you see it in action (the values are displayed at the bottom of the fiddle). Let's say you click on the checkbox name=> string2, the value of object['name']['string2'] will correspond to the state of the checkbox, which will be automatically watched by the ng-model.

When you have this, it's quite easy to modify each checkbox with your controller, so I added a little search function in order to show it in action, you can search a list of words separated with a space in the search box, then clicking on search will check the matching checkboxes

On the HTML side it's not a big modification (sorry I'm not familiar with your templates, it will be straight HTML)

    <div ng-repeat='(key,val) in uniqueLists'>
       <form name='{{key}}'>
       {{key}}
            <p ng-repeat='value in val'>
                <input type='checkbox' ng-model='selectedData[key][value]' />{{value}}
            </p>
        </form>

    </div>

And on the controller side, this is how I initialize the models :

$scope.selectedData={};
for (var i in $scope.uniqueLists)
{
 $scope.selectedData[i]={}
     for(var j in $scope.uniqueLists[i])
     {
         $scope.selectedData[i][$scope.uniqueLists[i][j]]=false;
     }
}

The last part, the search function is only made of loops to iterate all the search/model values, I think this is what you will have to modify in order to match your own search controller

Is that what you wanted ?

Tourniquet answered 28/7, 2013 at 15:16 Comment(3)
This is great, and yes it's what I wanted. I never thought to put the models in an object like you did, great idea. One thing I don't understand, when the HTML renders all of the ng-model names for the checkboxes are still selectedData[key][value], and are not rendered to selectedData[name][string1]. Why is that? And yet Angular works with it as though its ng-model name IS selectedData[name][string1]. Bizarre.Cantor
Also I wish I could upvote you more, this was a really great and thorough answer, especially with the added search that you implemented.Cantor
Thanks a ton buddy! Had searched everywhere but no solution founded, best solution.!Artemis
M
0

@DotDotDot

I am faced with the same pb with _dynamic_names_, and fully understand the author of Q. With you example almost everything works fine EXCEPT (!) submitting. Please take a look into attached Screenshot.

With this example the ng-model have to be dynamic, like: selectedData_A_1, selectedData_B_2, selectedData_C_3, e.t.c ...

...only then, in case of using the HTML-Form-Submit will be able to decode the value of checkbox in relation with the name.

enter image description here

Marigraph answered 16/9, 2014 at 13:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.