How to Add Onclick for many buttons instantiated from a loop?

I got the files from the Application.persistentDataPath and showed it into a list.Each name in the list contains a delete button.When I click the delete button the specified file need to be deleted.The below code is not working.I have dragged and dropped delete button from the prefab.

public Button delbutton;

public void ListMap()
{
    panellist.SetActive(true);
    string mainpath = Application.persistentDataPath;
    DirectoryInfo dir = new DirectoryInfo(mainpath);

    for(int i = 1;i<=info.Length;i++)
    {
        GameObject lisobj = Instantiate(prefabpanellist);

            lisobj.transform.SetParent(Parentcontent);
            number.text = i.ToString();
            mapnamedb.text =info[i-1].Name;

        delbutton.onClick.AddListener(() => Deleteinformation(i));


    }

}



void Deleteinformation(int ivalue)
{
    string mainpath = Application.persistentDataPath;
    File.Delete(mainpath + info[ivalue-1]);
    Debug.Log("ivalue is = "+ivalue);
}

If someone could explain in a simple way would be helpful

It’s not working because you’re adding all listeners to the prefab instead of adding it to every prefab instance you’re creating. You should get the button component from every instance and add listener to it:

var button = listobj.GetComponent<Button>();
if(button != null) {
    button.OnClick.AddListener(...);
}

And if your buttong component is not on the root object in the prefab hierarchy, you should find that object in the instance hierarchy and get component from that instance.

This is the code I tried.

 public void ListMap()
    {
        panellist.SetActive(true);
        string mainpath = Application.persistentDataPath;
        DirectoryInfo dir = new DirectoryInfo(mainpath);
       // FileInfo[] info = dir.GetFiles("*.json");


        info = dir.GetFiles("*.json");
    
        int icopy=0;
        for(int i = 1;i<=info.Length;i++)
        {
             lisobj = Instantiate(prefabpanellist);

                lisobj.transform.SetParent(Parentcontent);
                number.text = i.ToString();
                mapnamedb.text =info[i-1].Name;
                 icopy = i;
            Debug.Log("ivalue forloop = " + icopy);
            var button = lisobj.GetComponentInChildren<Button>();
            Debug.Log("Button name = "+button.name);
            if (button != null)
            {
                button.onClick.AddListener(() => Deleteinformation(icopy));
            }

        }

    
     
    }

    public void Deleteinformation(int ivalue)
    {
        Debug.Log("ivalue is = " + ivalue);
        string mainpath = Application.persistentDataPath;
       // File.Delete(mainpath + info[ivalue-1]);
        // Debug.Log("ivalue is = "+ivalue);
        File.Delete(mainpath + info[ivalue - 1]);

    }

Error coming is DirectoryNotFoundException: Could not find a part of the path “/Users/ar/Library/Application Support/Systi/Mapping/Users/ar/Library/Application Support/Systi/Mapping/Modeldetails1.json”.

When I click the different buttons it is trying to delete the same file-Modeldetails1.json

That’s how closures working in c#. All the closures reference the same icopy variable. When the for loop is completed, icopy contains last value and all your closures will use that value.

To solve this and many other issues in your code, you should change your architecture. Create a signle script called FileView and put it to the root object of your prefab. Code label, button, file path, icon and others as properties of that script. Make Delete method in that script and subscribe it to the delete button’s event. After that all you need to do to is to instantiate this prefab and set file info to it.

But still I will require the for loop for Instantiating the List objects and I need to add Listner from there only.Right?

You still need loop to instantiate multiple objects, but you generally need loops to do something multiple times, so it’s okay here. No, you don’t need to add event listeners in the loop, configure them once on the prefab itself instead using the editor, not code.

declare the variables inside the loop:

public void ListMap()
    {
        panellist.SetActive(true);
        string mainpath = Application.persistentDataPath;
        DirectoryInfo dir = new DirectoryInfo(mainpath);
       // FileInfo[] info = dir.GetFiles("*.json");
        info = dir.GetFiles("*.json");
int icopy=0; //dont declare here
     
for(int i = 1;i<=info.Length;i++)

           int icopy=0; //declare it here
          
 lisobj = Instantiate(prefabpanellist);
                lisobj.transform.SetParent(Parentcontent);
                number.text = i.ToString();
                mapnamedb.text =info[i-1].Name;
                 icopy = i;
            Debug.Log("ivalue forloop = " + icopy);
            var button = lisobj.GetComponentInChildren<Button>();
            Debug.Log("Button name = "+button.name);
            if (button != null)
            {
                button.onClick.AddListener(() => Deleteinformation(icopy));
            }
        }
 
    }
    public void Deleteinformation(int ivalue)
    {
        Debug.Log("ivalue is = " + ivalue);
        string mainpath = Application.persistentDataPath;
       // File.Delete(mainpath + info[ivalue-1]);
        // Debug.Log("ivalue is = "+ivalue);
        File.Delete(mainpath + info[ivalue - 1]);
    }