0
votes

comportement étrange (éléments html disparaissant) dans Blazor (serveur), éventuellement blazor.server.js

Voir un comportement étrange dans une application Blazor (serveur) sur laquelle je travaille. Nouveau dans cette technologie, et pas terrible pour le développement Web pour commencer, mais je suis assis ici.

Le problème est que pour une raison quelconque, et en ne déboguant aucun code que je déclenche délibérément, Blazor supprime / ajoute des éléments HTML sur ma page sans rappeler le code C # du serveur pour autant que je sache. Il ne le fait que pour 1 des 3 éléments de sélection html, qui sont codés exactement de la même manière sur la page. Cet élément de sélection particulier semble déclencher la logique de filtrage que j'ai en C #, mais pour la vie de moi, je ne peux pas comprendre comment il le fait. Et même si c'est le cas, ce n'est pas exactement correct dans ce qu'il fait en ce qui concerne ma logique C #.

Ce qui est supprimé, ce sont les span / boutons rendus dans @foreach ci-dessous, mais UNIQUEMENT lorsque vous cliquez sur quelque chose dans l'élément de sélection "Codes d'état". Cela ne se produit qu'après le premier filtrage qui rend le contenu dans @foreach la première fois. Après cela, la modification de la sélection 'Code d'état' commence à modifier le côté client HTML, mais uniquement pour cet élément de sélection. Pas les deux autres. Remarquez que j'ai actuellement le ApplyFilter commenté en C #, il se déclenche uniquement lorsque vous cliquez sur le bouton «Rechercher». Les 2 autres éléments de sélection se comportent exactement comme prévu, c'est-à-dire que rien ne se passe avec @foreach tant que je ne clique pas physiquement sur le bouton «Rechercher».

J'ai mis un point d'arrêt sur le changement de sous-arbre dans les outils de développement du navigateur pour ce bloc @foreach, et ce que je décris est ce qui se passe dans cet événement et le point d'arrêt atteint. Les 1er et 3ème éléments de sélection ne provoquent jamais le changement du sous-arbre, le 2ème le fait. La rupture de changement de sous-arborescence indique que blazor.server.js appelle «removeChildElement».

Je n'ai actuellement aucun côté client javascript, autre que ce que Blazor pourrait faire. Donc, c'est pur côté serveur Blazor, HTML / C # avec les bits de script Razor-ish pour rendre la page.

Merci d'avance pour toute réflexion sur la façon de déboguer cela plus loin, ou de comprendre ce que j'ai fait de mal ici ... ce qui peut être BEAUCOUP dans la façon dont j'ai écrit cette application.

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();
}    

Et voici le code C # qui gère les différents événements @onchange.

    <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 && 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 && 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 && 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>   


2 commentaires

Avez-vous essayé de mettre un point d'arrêt dans le code C # dans Visual Studio et de voir si le code s'exécute comme prévu? Vous pouvez mettre un point d'arrêt sur toutes vos méthodes et voir ce qui se passe.


Oui. Aucun code C # n'est en cours d'exécution lorsque vous cliquez / sélectionnez l'un des éléments (sur le dernier code que j'ai publié ci-dessous) dans les éléments de sélection. Et avant ce dernier changement, le seul code en cours d'exécution était de définir la variable privée de sauvegarde pour l'élément de sélection correspondant. Vous devez cliquer sur le bouton «Rechercher» pour que le C # fasse quoi que ce soit. Je ne sais pas comment décrire ce qui se passe, mais c'est comme à un moment donné, il a créé du javascript et il exécute un filtrage côté client pour cet élément de sélection unique. Comme je l'ai dit, les 2 autres ne se comportent pas de cette façon. Rend ZERO sens.


3 Réponses :


1
votes

C'est une bonne idée de lier @ key = "quelque chose d'unique" aux composants et éléments dans des boucles. Cela aide Blazor à savoir ce qui a changé. Mettez-le sur la travée car il est en boucle


1 commentaires

Merci, ajouté cela avec une valeur unique w / dans les limites de ce <li> <div>.



1
votes

Merci. Je viens de commenter le site et les sélections correspondantes, même comportement. La première sélection du code d'état, et les allers-retours entre les options, ne font rien. Cliquez sur "Rechercher" pour filtrer comme prévu puis sur le premier clic sur "Rechercher". Ensuite, si je repasse à l'élément «tous» dans la liste des codes d'état, tous les boutons disparaissent. Cliquer correctement sur les options supplémentaires filtre. C'est tellement étrange.

Code révisé ci-dessous ...

    <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 && 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 && 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 && 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();
}     *@


2 commentaires

"tous les boutons disparaissent" Quels boutons? Voulez-vous dire les éléments de l'élément de sélection? Veuillez mettre à jour votre réponse avec le code de la méthode _ApplyFilter.


Les boutons sont ceux qui sont rendus dans le tout dernier LI / DIV en bas du HTML. Ordre des événements ici. Chargement de la page, boutons remplis, cliquez sur l'élément 1 dans la sélection du code d'état. Cliquez sur «Rechercher». Le code C # déclenche _ApplyFilter. La liste des boutons est filtrée. Cliquez de nouveau sur l'élément par défaut «tous» dans le code d'état, les boutons disparaissent (rien ne devrait se produire). Ils sont supprimés 1 à la fois, tous côté client, aucun code C # n'est déclenché.



0
votes

Désolé, par «bouton», je voulais dire le DIV tout en bas du HTML qui contient les éléments SPAN en utilisant la classe bootstrap btn pour le style. Code complet pour la partie de la barre latérale de l'application.

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) && 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) && 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 && 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");
}

@code {

<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
            @* &nbsp&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
            @* &nbsp&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
            @* &nbsp&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 && 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 && 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 && 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>   

}


0 commentaires