SBB
SBB

Reputation: 8970

Angular - Using ngFor on a select input is causing strange behavior

I have a very simple, or so I thought, select input. It is getting its values for the option tags by using ngFor. I also am using [selected] to set the value of the input based on what the user has selected.

The Behavior:

When I click on the dropdown, it is flashing like it is loading or doing something twice. It doesn't have the normal opening event like I remember seeing. Once it is open, I can pick a value just fine. If I go back and re-open the options again, it is setting the selected option back to what is currently selected in the object. <--- This may be normal behavior since I am telling it what selected should be. Ideally though, this should be set one time and then not reset each time it is opened.

HTML:

<select class="form-control input-sm" *ngIf="inEditMode(r.RuleParentID, a.AttributeID)" (change)="updateOperator($event)">
  <option value="">Select Operator</option>
  <option *ngFor="let o of fetchOperatorList(a.AttributeID)" [value]="o.OperatorID" [selected]="o.OperatorID === a.OperatorID">{{ o.OperatorName }}</option>
</select>

fetchOperatorList() method:

fetchOperatorList(attributeID) {

        let temp = Array();

        // Scan our attributes
        for (const key in this.globalMapData.attributes) {

            // Find attribute by property
            if (this.globalMapData.attributes.hasOwnProperty(key)) {

                // If this attribute is the one we are searching, continue
                if (this.globalMapData.attributes[key].AttributeID == attributeID) {

                    // Loop over the operators for this attribute
                    let ops = this.globalMapData.attributes[key].attributeOperators.a;
                    for (var i = 0; i < ops.length; i++) {

                        // Push possible attribute operators to an array
                        temp.push({
                            OperatorID: ops[i].OperatorID,
                            OperatorName: ops[i].OperatorName,
                            SqlOperator: ops[i].SqlOperator
                        });

                    }

                }
            }
        }
        return temp;
    }

Example Image:

enter image description here

Goal:

First, I have no idea why it is doing the whole appearance of double loading, seems off...

Is there also a way to set the default selected value but not reset it back every time the input is opened? To get to this point, the user clicked "Edit" on the page and was provided the select to change the option. If they happen to pick the wrong thing and open it again, I don't want it to reset back to the original.

Update:

I removed the ngIf on the select itself as well as the onChange to help narrow it down. The issue still occurs. I removed the selected property and only kept [value]. I put in a console.log in the ngFor function and thats where it was interesting. It appears to be running two times, multiple times. I am going to look at this function a little more and see what is being output but that's gotta be part of the problem.

Update2:

This select is wrapped within another ngFor that is looping over all of my user records. What appears to be happening is when the ngIf becomes true, it calls the ngFor on the select options for the number of times it was iterated over.

<tr class="attribute" *ngFor="let a of r.attributes.attribute" [class.info]="inEditMode(r.RuleParentID, a.AttributeID)">
 <td class="small col-md-2 attr"><strong>{{ a.AttributeName }}</strong></td>
 <td class="small col-md-1 oper">
   <span *ngIf="!inEditMode(r.RuleParentID, a.AttributeID)">
    <strong>{{ a.OperatorName}}</strong>
   </span>
   <select class="form-control input-sm" *ngIf="inEditMode(r.RuleParentID, a.AttributeID)">
   <option value="">Select Operator</option>
     <option *ngFor="let o of fetchOperatorList(a.AttributeID)" [value]="o.OperatorID">{{ o.OperatorName }}</option>
   </select>
 </td>
</tr>

Upvotes: 0

Views: 800

Answers (1)

cyr_x
cyr_x

Reputation: 14257

Sometimes this happens in development mode, it's because angular's changedetection is running twice for each change. This is likely causing the flash, because you're creating a new reference of the array and the ngForOf directive is reflecting that. You could try to tell the ngForOf directive to track it's children by index without taking the reference into account via trackBy and a function.

trackByIndex(index: number, value: any) {
  return index;
}

And inside your template:

*ngFor="...;trackBy:trackByIndex"

Upvotes: 1

Related Questions