onValueChanged Dropdown in loop

I am having a problem with dropdowns which I add them programatically, more precise with the onValueChanged event. No matter which dropdown value I change in game the parameter used by onValueChanged is the last row instantiated.

Any idea?

int inc = 0;
foreach (Report report in reports)
{
    inc++;
    GameObject row = Instantiate(reportRow) as GameObject;
    row.name += " - " + report.id;
    row.transform.parent = rows;
    row.AddComponent<Report>().SetValues(report);
    row.transform.Find("Status").GetComponent<Dropdown>().onValueChanged.AddListener(delegate { StatusChange(row.transform); });
}

Uhm, that shouldn’t happen in your case since you already are using a local variable (row) that is declared inside the foreach loop. So the closure you’re creating should close around the current “row” variable. Are you sure that this is your exact code?

I’m a bit confused. What exactly is “reportRow”? Isn’t it a prefab? Why doesn’t it already contain a Report script? By adding the report script directly to your prefab you could do a lot of those initialization inside the Report script. You can also setup the required links in the inspector. By adding a public Dropdown variable to the Report script you can simply setup the link to the dropdown field in the editor.

Next thing that seems a bit strange is, if Report is a Component (MonoBehaviour), where are those report scripts attached to that are referenced in the “reports” array / collection? Keep in mind that you shouldn’t create MonoBehaviours with “new”. To initialize a component with values from another component of the same type seem a bit odd.

Thank you for your response.
Report is a class that maps a table in DB. I’ve changed the code to remove the new assignment to a MonoBehaviour class. Same behavior unfortunately :frowning:
Here is the new code and the report class:

var r = JSON.Parse(result.text);
int nr = r["rows"].Count;

Transform rows = gameMySuggestionsWindow.Find("Table").Find("Rows Scroll View").Find("Viewport").Find("Content");
for (int i = 0; i < nr; i++)
{
    GameObject row = Instantiate(reportRow) as GameObject;
    row.name += " - " + r["rows"]*["id"];*

row.transform.parent = rows;
row.AddComponent().SetValues(r[“rows”]);
row.transform.localPosition = new Vector3(0, -i * 60, 0);
Report report = row.GetComponent();
row.transform.FindChild(“Number Text”).GetComponent().text = i.ToString();
row.transform.FindChild(“Level Text”).GetComponent().text = GameManager.Instance.scenes[report.mapId];
row.transform.FindChild(“Type Text”).GetComponent().text = report.reportType.ToString();
Transform desc = row.transform.Find(“Scroll View”).Find(“Viewport”).Find(“Content”).Find(“Description Text”);
desc.GetComponent().text = report.description;
row.transform.FindChild(“Status”).GetComponent().value = reportStatus[report.status];
row.transform.Find(“Status”).GetComponent().onValueChanged.AddListener(delegate { StatusChange(row.transform); });
}
and the Report class
public class Report : MonoBehaviour
{
public int id;
public Vector3 characterPosition;
public string reportType;
public string description;
public string status;
public string dateAdded;

public void SetValues(JSONNode r)
{
id = Convert.ToInt32(r[“id”]);
string[] pos = Convert.ToString(r[“character_position”]).Split(‘,’);
if (pos.Length > 0)
{
characterPosition = new Vector3(Convert.ToSingle(pos[0]), Convert.ToSingle(pos[1]), Convert.ToSingle(pos[2]));
}
else
{
characterPosition = Vector3.zero;
}
reportType = Convert.ToString(r[“report_type”]);
description = Convert.ToString(r[“description”]);
status = Convert.ToString(r[“status”]);
dateAdded = Convert.ToString(r[“date_added”]);
}
}