nathan10802
nathan10802

Reputation: 45

Using parent to call a method from the components Blazor

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?

Upvotes: 2

Views: 441

Answers (1)

Dimitris Maragkos
Dimitris Maragkos

Reputation: 11302

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 @key="d.ID" @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 manually update the _fileFilterRefs dictionary whenever you remove an item from filters list to keep them synchronized. E.g.

private void Delete(FileFilter fileFilter)
{
    _filters.Remove(fileFilter);

    _fileFilterRefs.Remove(fileFilter.ID);
}

You should clear the _fileFilterRefs dictionary whenever you set the filters list to a new list. E.g.

private async Task RefreshFilters()
{
    _fileFilterRefs.Clear();

    _filters = await filterService.GetFileFilters();
}

But you don't have to do the same thing when you add a new item to the filters list (_filters.Add(...)). In that case it's handled automatically.

In summary:

  • filters.Add(new FileFilter()) -> do nothing.
  • filters.Remove(fileFilter) -> remove fileFilter.ID key from _fileFilterRefs
  • filters = new List() -> clear _fileFilterRefs before setting the list

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

Upvotes: 3

Related Questions