Quick question...
Is the following code "legal" in Blazor? I mean can I trust that the currentTag
variable will always be right, or do I have to "lock" it someway? Not sure how else to get the current item from the loop and use it in the code.
I have a foreach loop on a component and then saving the current item to a variable in my code below. The variable is used immediately after to bind to another childcomponent
@if (DataTags != null)
{
@foreach (var dataTag in DataTags)
{
// Set currentDataTag
@{currentDataTag = dataTag;
}
<TagValueForm @bind-TagKeyValuePair="TagKeyValuePair" DataTag="dataTag"></TagValueForm>
}
}
@code {
[Parameter]
public ICollection<Tag> DataTags { get; set; }
[Parameter]
public IDictionary<string, string> Tags { get; set; }
// Use the current tag:
private Tag currentDataTag;
private KeyValuePair<string, string> _tagKeyValuePair;
private KeyValuePair<string, string> TagKeyValuePair
{
get
{
if (currentDataTag != null) //would never be null.. or?
{
return new KeyValuePair<string, string>(Tags.Keys.Where(x => x == currentDataTag.Name).FirstOrDefault(), Tags[currentDataTag.Name]);
}
else
{
return _tagKeyValuePair;
}
}
set
{
//Update tag dictionary
_tagKeyValuePair = value;
Tags[_tagKeyValuePair.Key] = _tagKeyValuePair.Value;
TagsChanged.InvokeAsync(Tags);
}
}
}
protected async override Task OnParametersSetAsync()
{
if (Tags == null)
{
Tags = new Dictionary<string, string>();
}
if (DataTags != null)
{
Tags = DataTags.ToDictionary(x => x.Name, x => { return Tags.ContainsKey(x.Name) ? Tags[x.Name] : null; });
}
await base.OnParametersSetAsync();
}
It seems to work with my tests so far, but unsure if I'm just lucky :) Could try to do some delays here and there to test more.
Your @foreach
block is setting the currentDataTag
field for every iteration, so in the end the value for the last iteration is where it stops. Your code is working, which is good, but now you have a field with a value that could misrepresent what you are trying to do later on.
I'd probably remove this part:
// Set currentDataTag
@{currentDataTag = dataTag;
}
and find a way to do everything that needed to be done originally with currentDataTag
in the same loop iteration. If it's bound to another component, render that component also inside the loop. That way you can avoid any issues that could arise as a result of depending on state outside the loop, i.e. what if that value was changed from somewhere else, or read from at an unexpected time.
As a last resort, at the end of each loop iteration, set that currentDataTag
to null or a base value so you can't read stale or incorrect data later on. Post some more code for us for better context if this doesn't help.