странное поведение (исчезновение элементов html) в Blazor (сервер), возможно blazor.server.js

#c# #html #blazor

#c# #HTML #blazor

Вопрос:

Вижу какое-то странное поведение в приложении Blazor (сервер), над которым я работаю. Новичок в этой технологии и не настолько хорош в веб-разработке для начала, но вот я сижу.

Проблема в том, что по какой-то причине, и из-за отсутствия кода, который я намеренно запускаю, Blazor удаляет / добавляет HTML-элементы на мою страницу без обратного вызова кода C # сервера, насколько я могу судить. Это делается только для 1 из 3 элементов выбора html, которые кодируются точно так же на странице. Этот конкретный элемент select, похоже, запускает логику фильтрации, которая у меня есть в C #, но, хоть убейте, я не могу понять, как он это делает. И даже если это так, это не совсем правильно в том, что он делает, поскольку он относится к моей логике C #.

Удаляются кнопки span /, отображаемые в @foreach, показанном ниже, но ТОЛЬКО при нажатии на что-либо в элементе выбора «Коды состояния». Это происходит только после первой фильтрации, которая отображает содержимое в @foreach в первый раз. После этого изменение выбора ‘Status Code’ начинает изменять клиентскую часть HTML, но только для этого одного элемента select. Не два других. Обратите внимание, что в настоящее время у меня есть applyFilter, закомментированный в C #, он срабатывает только при нажатии кнопки «Поиск». Остальные 2 элемента select ведут себя точно так, как ожидалось, то есть с @foreach ничего не происходит, пока я физически не нажму кнопку «Поиск».

Я установил точку останова для изменения поддерева в инструментах разработчика браузера для этого блока @foreach, и я описываю, что происходит в этом событии и достигается точка останова. 1-й и 3-й элементы выбора никогда не приводят к изменению поддерева, 2-й делает. Разрыв изменения поддерева указывает на то, что blazor.server.js вызывает ‘removeChildElement’.

В настоящее время у меня нет клиентской части javascript, кроме того, что может делать blazor. Итак, это чистая серверная часть Blazor, HTML / C # с битами сценариев Razor-иш для рендеринга страницы.

Заранее спасибо за любые мысли о том, как отладить это дальше, или выяснить, что я здесь сделал не так … чего может быть МНОГО в том, как я написал это приложение.

     <ul class="nav flex-column">
    <li class="nav-item px-3">   
        <select class="form-control" @onchange="OnChangeFilterSite">
            <option value="all" selected>Select Site :</option>
            @foreach (string item in RtuServiceData.Sites) {
                if (filterSite != null amp;amp; filterSite == @item) {
                    <option selected value="@item">@item</option>
                }
                else {
                    <option value="@item">@item</option>    
                }
            }                
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @onchange="OnChangeFilterStatusCode">
            <option value="all" selected>RTU Status :</option>
            @foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
                if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
                    <option selected value="@item.Code">@item.Description</option>
                }
                else {
                    <option value="@item.Code">@item.Description</option>
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @onchange="OnChangeFilterMatchingOption">
            <option value="all" selected>Matching Option :</option>
            @foreach (string item in RtuServiceData.MatchingOptions) {
                if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
                    <option selected value="@item">@item</option>
                }
                else {
                    <option value="@item">@item</option>    
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <label class="text-white"><b>Filter :</b></label>
        <input type="text" class="form-control" @onchange="OnChangeFilterName"/>
        <br>
        <button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
        <br><br>       
    </li>
    <li class="nav-item px-3">
        <div style="height: 300px; overflow: auto; padding-right: 15px">
            @foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
                <span class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
            }
        </div>
    </li>
</ul>   
  

И вот код C #, который обрабатывает различные события @onchange.

 private string filterSite;
public void OnChangeFilterSite(ChangeEventArgs e)
{
    filterSite = e.Value.ToString();
    //_ApplyFilter();
}

private string filterStatusCode;
public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
    filterStatusCode = e.Value.ToString();
    //_ApplyFilter();
}        

private string filterMatchingOption;
public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
    filterMatchingOption = e.Value.ToString();
    //_ApplyFilter();
}    

private string filterName;
public void OnChangeFilterName(ChangeEventArgs e)
{
    filterName = e.Value.ToString();
    //_ApplyFilter();
}    
  

Комментарии:

1. Вы пробовали ставить точку останова в коде C # в Visual Studio и проверять, выполняется ли код так, как вы ожидаете? Вы можете установить точку останова для всех своих методов и посмотреть, что происходит.

2. ДА. При нажатии / выборе одного из элементов (в последнем коде, который я опубликовал ниже) в элементах выбора не выполняется код C #. И до этого последнего изменения единственным выполнявшимся кодом была установка резервной частной переменной для соответствующего элемента select . Вы должны нажать кнопку «Поиск», чтобы вызвать C # для выполнения каких-либо действий. Я не уверен, как описать, что происходит, но похоже, что в какой-то момент он каким-то образом создал некоторый javascript и запустил фильтрацию на стороне клиента для этого 1 отдельного элемента select. Как я уже сказал, остальные 2 ведут себя иначе. Не имеет НИКАКОГО смысла.

Ответ №1:

Хорошей идеей будет привязать @key=»что-то уникальное» к компонентам и элементам в циклах. Это помогает Blazor узнать, что изменилось. Поместите его в диапазон, поскольку он находится в цикле

Комментарии:

1. Спасибо, добавил это с уникальным значением w /в пределах этого <li> <div> .

Ответ №2:

Спасибо. Просто прокомментировал сайт и соответствующие выборки, такое же поведение. Первый выбор кода состояния и переход между опциями ничего не дает. Нажатие кнопки «Поиск» фильтрует, как и ожидалось, затем при первом нажатии кнопки «Поиск». Затем, если я переключусь обратно на элемент «все» в списке кодов состояния, все кнопки исчезнут. Нажатие на дополнительные параметры фильтрует правильно. Это так странно.

Пересмотренный код ниже…

     <ul class="nav flex-column">
    <li class="nav-item px-3">   
        <select class="form-control" @bind="@filterSite">
            <option value="all" selected>Select Site :</option>
            @foreach (string item in RtuServiceData.Sites) {
                if (filterSite != null amp;amp; filterSite == @item) {
                    <option @key="@item" selected value="@item">@item</option>
                }
                else {
                    <option @key="@item" value="@item">@item</option>    
                }
            }                
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @bind="@filterStatusCode">
            <option value="all" selected>RTU Status :</option>
            @foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
                if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
                    <option @key="@item.Code" selected value="@item.Code">@item.Description</option>
                }
                else {
                    <option @key="@item.Code" value="@item.Code">@item.Description</option>
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @bind="@filterMatchingOption">
            <option value="all" selected>Matching Option :</option>
            @foreach (string item in RtuServiceData.MatchingOptions) {
                if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
                    <option @key="@item" selected value="@item">@item</option>
                }
                else {
                    <option @key="@item" value="@item">@item</option>    
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <label class="text-white"><b>Filter :</b></label>
        <input type="text" class="form-control" @bind="@filterName"/>
        <br>
        <button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
        <br><br>       
    </li>
    <li class="nav-item px-3">
        <div style="height: 300px; overflow: auto; padding-right: 15px">
            @foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
                <span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
            }
        </div>
    </li>
</ul>   

private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
    filterSite = e.Value.ToString();
    //_ApplyFilter();
} *@

private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
    filterStatusCode = e.Value.ToString();
    //_ApplyFilter();
}         *@

private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
    filterMatchingOption = e.Value.ToString();
    //_ApplyFilter();
}     *@

private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
    filterName = e.Value.ToString();
    //_ApplyFilter();
}     *@
  

Комментарии:

1. «все кнопки исчезают» Какие кнопки? Вы имеете в виду элементы в элементе select ? Пожалуйста, обновите свой ответ кодом для метода _ApplyFilter .

2. Кнопки — это те, которые отображаются в самом последнем LI / DIV в нижней части HTML. Порядок событий здесь. Страница загружается, кнопки заполнены, нажмите пункт 1 в коде состояния выберите. Нажмите «Поиск». Код C # запускает _ApplyFilter . Список кнопок фильтруется. Нажмите назад к элементу «все» по умолчанию в коде состояния, кнопки исчезнут (ничего не должно произойти). Они удаляются по одному за раз, на стороне клиента, код C # не запускается.

Ответ №3:

Извините, под «кнопкой» я имел в виду DIV в самом низу HTML, который содержит элементы SPAN, использующие класс bootstrap btn для стилизации. Полный код для боковой панели приложения.

 <div>
<ul class="nav flex-column">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="rtu">
            <span class="oi oi-home" aria-hidden="true"></span> RTU
            @* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
        </NavLink>           
    </li>      
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="analogs">
            <span class="oi oi-list-rich" aria-hidden="true"></span> Analogs
            @* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
        </NavLink>
    </li>
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="digitals">
            <span class="oi oi-list-rich" aria-hidden="true"></span> Digitals
            @* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
        </NavLink>
    </li>       
</ul>
<br>
<ul class="nav flex-column">
    <li class="nav-item px-3">   
        <select class="form-control" @bind="@filterSite">
            <option value="all" selected>Select Site :</option>
            @foreach (string item in RtuServiceData.Sites) {
                if (filterSite != null amp;amp; filterSite == @item) {
                    <option @key="@item" selected value="@item">@item</option>
                }
                else {
                    <option @key="@item" value="@item">@item</option>    
                }
            }                
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @bind="@filterStatusCode">
            <option value="all" selected>RTU Status :</option>
            @foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
                if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
                    <option @key="@item.Code" selected value="@item.Code">@item.Description</option>
                }
                else {
                    <option @key="@item.Code" value="@item.Code">@item.Description</option>
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <select class="form-control" @bind="@filterMatchingOption">
            <option value="all" selected>Matching Option :</option>
            @foreach (string item in RtuServiceData.MatchingOptions) {
                if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
                    <option @key="@item" selected value="@item">@item</option>
                }
                else {
                    <option @key="@item" value="@item">@item</option>    
                }
            }
        </select>
    </li>
    <li class="nav-item px-3">
        <label class="text-white"><b>Filter :</b></label>
        <input type="text" class="form-control" @bind="@filterName"/>
        <br>
        <button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
        <br><br>       
    </li>
    <li class="nav-item px-3">
        <div style="height: 300px; overflow: auto; padding-right: 15px">
            @foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
                <span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
            }
        </div>
    </li>
</ul>   
  

@code {

 private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
    filterSite = e.Value.ToString();
    //_ApplyFilter();
} *@

private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
    filterStatusCode = e.Value.ToString();
    //_ApplyFilter();
}         *@

private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
    filterMatchingOption = e.Value.ToString();
    //_ApplyFilter();
}     *@

private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
    filterName = e.Value.ToString();
    //_ApplyFilter();
}     *@

protected override async Task OnInitializedAsync()
{
    await Task.Run(_Load);
}

protected void _Load() {  
    RtuServiceData.RTUs = RtuService._GetRtuList();
    RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs;
}

private void _ApplyFilter() {

    RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs;  //get the full list from the singleton
    
    //only filter on site when it's one of the values in the list
    if (!string.IsNullOrEmpty(filterSite) amp;amp; RtuServiceData.Sites.Contains(filterSite)) {
        RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.SITE == filterSite).ToList();
    }

    //only filter on status code when it's one of the values in the list
    if (!string.IsNullOrEmpty(filterStatusCode) amp;amp; RtuServiceData.StatusCodes.Select(x => x.Code).Contains(filterStatusCode)) {
        RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Accepted.ACCEPTED_STATUS == filterStatusCode);
    }

    //only filter on matching option when it's one of the values in the list
    switch (filterMatchingOption) {
        case "100% Match":
            RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 100);
            break;
        case "< 100% Match":
            RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT > 0 amp;amp; r.Proposed.MATCH_PERCENT < 100);
            break;
        case "No Match":
            RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 0);
            break;
        default: // default: provides the same functionality as checking filterSite and filterStatusCode against legit values above
            break; 
    }

    //only filter on name when it's populated
    if (!string.IsNullOrEmpty(filterName)) {
        RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.RTU.ToUpper().StartsWith(filterName.ToUpper()));
    }  

}

private void _SetRtu(int id) {
    RtuServiceData.SelectedRtu = null;
    NavigationManager.NavigateTo("/");
    RtuServiceData.SelectedRtu = RtuService._GetRtu(id);
    NavigationManager.NavigateTo("rtu");
}
  

}