Home > Net >  Using parent to call a method from the components Blazor
Using parent to call a method from the components Blazor

Time:09-02

I have this method in my components called ClearFiles(string PathName) which I currently call by clicking one of the buttons on the component, but now I'm trying to call of them at once but I cannot figure out how to do this. Calling a single ClearFiles method from the component works perfectly, but I'm not quite sure how to call all these methods at once using the parent class. I have made a button in the parent class with the name of ForceClean which I'm hoping can be pressed to call all of the components clear files function.

I create the components in the parent class using a for loop in my PageFileCleaner.razor file like this:

@foreach (var d in filters)
{
     <CompFileFilter FileFilter="d" OnDelete="Delete" ></CompFileFilter>
}

Where filters is a List of type FileFilter which is in the namespace Common.DB. This is how it is declared in the parent class:

private List<FileFilter> filters { get; set; }

And is populated with data from my database using:

        using var context = _db.CreateDbContext();
        filters = await context.FileFilters.AsNoTracking().ToListAsync();
        foreach( var filter in filters)
        {
            FileFilter f = new FileFilter();
        }

And this Parameter (in the child class) is what i use to get the values from that row in the database using FileFilter.Pathname or FileFilter.ID for example:

    [Parameter]
    public FileFilter FileFilter { get; set; }

Database / FileFilter object class:

namespace Common.DB
{
    public class FileFilter
    {
        [Key]
        public int ID { get; set; }
        public string TimerChoice { get; set; }
        public bool IsLoading;
        public string PathName { get; set; } = "";
        public string Extension { get; set; }
        //public string[] extensionList { get; set; }
       ...
    }
}

The clear files function is in my component/child CompFileFilter.razor file (took the code out for this example because its over a hundred lines of code). I'm creating the components in the parent class and each one will have this ClearFiles() method.

public async Task ClearFiles(string PathName)
{  
     filtering code... 
} 

How can I loop through my components from the parent class and call all of there ClearFiles() method?

CodePudding user response:

You can use a dictionary and store the reference of each CompFileFilter component. Then use the references to call the ClearFiles method. You can use the ID property of FileFilter for the dictionary keys.

PageFileCleaner.razor

@foreach (var d in filters)
{
    <CompFileFilter @ref="_fileFilterRefs[d.ID]" FileFilter="d" OnDelete="Delete"></CompFileFilter>
}

@code {
    private Dictionary<int, CompFileFilter> _fileFilterRefs = new Dictionary<int, CompFileFilter>();

    private async Task ForceClean()
    {
        // Execute ClearFiles one at a time.
        foreach (var item in _fileFilterRefs)
        {
            await item.Value.ClearFiles();
        }
        
        // Or execute them in parallel.
        //var tasks = _fileFilterRefs.Select(item => Task.Run(item.Value.ClearFiles));
        //await Task.WhenAll(tasks);
    }
}

ClearFiles method doesn't need PathName parameter. You can get the PathName from the FileFilter parameter.

CompFileFilter.razor

@code {
    [Parameter]
    public FileFilter FileFilter { get; set; }

    public async Task ClearFiles()
    {  
        var pathName = FileFilter.PathName;
        // filtering code... 
    } 
}

Edit:

You should clear the _fileFilterRefs dictionary before any change to the filters list. Because when the filters list changes the @foreach (var d in filters) { ... } will run again and add new references to the dictionary so before that you have to remove the old references.

https://github.com/dotnet/aspnetcore/issues/17361#issuecomment-558138782

CodePudding user response:

Copy and test...

Add a new property to your FileFilter class to hold a reference to the component it is assigned to:

public CompFileFilter Reference { get; set; } = new CompFileFilter();

CompFileFilter.razor

<button type="button" @onclick="Remove">Remove me</button>

@code {

    [Parameter]
    public FileFilter FileFilter { get; set; }

    [Parameter]
    public EventCallback<CompFileFilter> OnDelete { get; set; }

    private async Task Remove()
    {
        await OnDelete.InvokeAsync(this);
    }

    public async Task ClearFiles()
    {
        Console.WriteLine(FileFilter.PathName);

        await Task.CompletedTask;

    }
}

Note: "Remove me" button removes the current component from its parent

PageFileCleaner.razor

@foreach (var d in filters)
{
    <CompFileFilter @key="d"  @ref="d.Reference" FileFilter="d" OnDelete="Delete"></CompFileFilter>
}

<p>
    <button type="button" @onclick="Clean">Clean all</button>
</p>

@code {
    
    private List<FileFilter> filters = new List<FileFilter> { new FileFilter {ID=1, PathName="Path1" },
                                          new FileFilter {ID=2, PathName="Path2" },
                                          new FileFilter {ID=3, PathName="Path3" } };

    private void Delete(CompFileFilter compFileFilter)
    {        
        var fileFilter =
          filters.Where(fileFilter => fileFilter.Reference == compFileFilter).FirstOrDefault();
        filters.Remove(fileFilter);
      
    }

    private async Task Clean()
    {
        foreach (var filter in filters)
        {
            await filter.Reference.ClearFiles();
        }
    }
}
  • Related