Escolha uma Página
(Last Updated On: 13/10/2019)

Listas DropDown em Cascata (Cascading) usando o Select Tag Helper no CORE MVC

por | ago 18, 2017 | Desenvolvimento de Aplicações, Dicas, Tag Helpers | 0 Comentários

Neste artigo damos continuidade ao artigo de listas dropdown usando o tag helper SELECT. Fazer listas dropdown em cascata exige o uso de Jquery e chamadas Ajax.  Este artigo mostra como fazer isso, desde o setup do sistema até as rotinas do core MVC integradas ao javascript. Não é muito elementar. Mas funciona. Aqui vai o caminho das pedras.

Fazendo o setup do seu sistema CORE MVC no arquivo Startup.cs

Há muitos artigos na Internet que falam em Cascading (dropdown em cascata, um dependente do outro) – mas a maioria mostra o milagre mas não mostra o santo. Ao fazer uma chamada AJAX para o servidor, por questões de segurança, os navegadores modernos não permitem. Principalmente se a camada está em domínio diferente do domínio da sua aplicação. No meu caso, eu não conseguia acesso HTTP para a leitura de dados mesmo dentro do meu próprio ambiente de desenvolvimento. Não conseguia nem no LOCALHOST, resumindo.

Estudando os erros, vi que precisava autorizar a aplicação CORE MVC a ler o que eu queria, criando uma política de acesso para capturar dados de uma página fora da página que você está. Dei o nome de “MinhaPolitica” a essa autorização.

Então, minha primeira recomendação é preparar os serviços do Startup.cs para lerem o domínio – ou os domínios – que você quiser. Na parte de Configuração dos Serviços (ConfigureServices) inclua:

Configure Services
 public void ConfigureServices(IServiceCollection services)
 {
         //-seu conteúdo atual

        //-inclua DEPOIS de sservices.AddMvc();
   
        //detalhes em https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core
            services.AddCors(options =>
            {
                options.AddPolicy("MinhaPolitica",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            });
}

Configurando o serviço globalmente

Depois disso é preciso configurar o serviço. :

Configuração Global
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, Alicecapella119Context context)
{
//- seu conteúdo atual
// - inclua se não quiser definir isso em todos os controladores que vão receber ou fornecer dados para os selects (ou outras finalidades)
//https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas
 // global policy - assign here or on each controller
 app.UseCors("MinhaPolitica");
}

Configurando Ações (Actions) dos Controladores (Controllers)

Se quiser garantir o acesso no seu próprio controlador (Control), coloque ANTES da ação do seu Controle (controller) o EnableCors :

Configuração do Get no Action do Controller
 //para json
        [HttpGet]
        [EnableCors("MinhaPolitica")] // AQUI!!!
        public JsonResult PegaCompetencias(int Id)
        {

            List<SelectListItem>Lista = new List<SelectListItem>();
            var Dados = _context.CompetenciasBancoGeral
                    .Where(r => r.IdConsultoria == Id)
                    .OrderBy(r => r.TituloCompetencia)
                    .Select(r => new
                     { r.IdCompetenciaBanco, r.TituloCompetencia });
            foreach (var Linha in Dados)
            {
                Lista.Add(new SelectListItem()
                {
                    Value = Linha.IdCompetenciaBanco.ToString(),
                    Text = Linha.TituloCompetencia,
                    Selected = false
                });
            }
            return Json(Lista);
        }

Configurações Diferentes para ambiente de Desenvolvimento e Produção

Pronto. Temos certeza agora que as chamadas GET, em Ajax, vão chegar. Lendo o artigo em referência, você verá que pode definir diferentes políticas, uma para ambiente de desenvolvimento, outra par ambiente de produção e, ao invés de liberar geral como fiz aqui, fazer liberações para localhost, seu domínio ou outros domínios, tendo mais de uma política. Exemplo:

Configura&ccedil;&otilde;es para Desenvolvimento e Produ&ccedil;&atilde;o
if (env.IsDevelopment())
            {
                 services.AddCors(options =>
                 {
                   options.AddPolicy("MinhaPoliticaLocal",
                    builder => builder.AllowAnyOrigin("localhost")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
                 })
            }
            else
            {
                aservices.AddCors(options =>
                 {
                   options.AddPolicy("MinhaPoliticaRemota",
                    builder => builder.AllowAnyOrigin("meudominio.com.br")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
                 })
            
            }

Princípio Básico dos Selects em Cascata

Selects em cascata funcionam do seguinte modo. Há um select MESTRE e um select ESCRAVO. Quando um item é selecionado no Select MESTRE, todos os itens do Select ESCRAVO são filtrados por uma variável (tipo ID) da opção selecionada. Itens sem essa ID são desprezados e somente são mostrados no Select ESCRAVO os itens que apresentam o mesmo valor da ID selecionada.

Ao fazermos uma seleção no MESTRE, essa escolha pode ser monitorada pelo comando Jquerychange()“:

Jquery change()
$(document).ready(function() {
	$('#SelectConsultoria').change(function() {
		// aqui vai acontecer o recarregamento dos dados do 
                //select ESCRAVO

		console.log("clicou select consultoria e mudou");

		}
	});

A rotina em Jquery para recarregar o Select ESCRAVO

Quando o  Jquerychange()” percebe uma mudança no select MESTRE (no exemplo pelo select com id=”SelectConsultoria”, a sequência de ações é a seguinte:

  1. Limpa o select escravo, cuja Id é “SelectCompetencia” (no modelo de dados, cada Consultoria opera um conjunto de Competências), com a função jquery empty(). Não use remove(), que apaga o select inteiro e não s opções…;
  2. Acrescenta uma única linha com a função append(), tipo “Selecione uma Competência”;
  3. Força um refresh (algumas versões de navegador ficam mortinhas). Você faz o append() e a tela não muda. Esse aqui é um truque, forçando o DOM a atualizar o elemento com id “SelectCompetencia”. Usa uma função local chamada “redraw”;
  4. Monta a URL usando @Context.Request.Host do CORE MVC. Muita gente usa @Url, comigo não funcionou. A Url já passa o parâmetro que foi escolhido no Select Mestre. O pulo do gato, aqui, é que esse endereço tem o CONTROLADOR (controller)e a AÇÃO (Action) que tem de ser chamada para devolver, em formato Json, os dados filtrados. Sim, ela vai buscar no controller do CORE MVC ;
  5. Faz a chamada Ajax com ‘GET’, para buscar os dados.;
  6. Com o sucesso da conexão, coloca os dados em ‘data’ e manda processar numa função à parte chamada callbackFunction;
  7. A função callbackFunction popula o Select ESCRAVO novamente, O pulo do gato, aqui, é que ela no final remove uma linha que ficaria em branco.
  8. Essas rotinas ficam no miolo do @section Scripts { }, no final da sua página .CSHTML. Não esqueça de colocar <script> e </script>, ficando @section Scripts { <script> //todas as suas rotinas </script> }
Todas rotinas Jquery
$(document).ready(function() {
	$('#SelectConsultoria').change(function() {
		console.log('@Context.Request.Host');
		console.log("clicou select consultoria e mudou");
        //limpa seletc ESCRAVO
		$('#SelectCompetencia').empty();
		console.log("passou por remoção da lista");
		
		//Guarda opção que foi selecionada no Select MESTRE
		var OpcaoAtual = $(this).val();
		$('#SelectCompetencia').append($('<option></option>').val("0").html('Selecione uma Competência'));
		var x = document.getElementById("SelectCompetencia");
		var option = document.createElement("option");
		
		//Adiciona uma opção tipo Slecione um Valor
		//option.value = "0"
		x.add(option);
		
		//Mancada para forçar redraw - pode não ser necessário
		var element = document.getElementById('SelectCompetencia');
		var n = document.createTextNode(' ');
		var disp = element.style.display; // don't worry about previous display style
		element.appendChild(n);
		element.style.display = 'none';
		setTimeout(function() {
			element.style.display = disp;
			n.parentNode.removeChild(n);
		}, 20); // you can play with this timeout to make it as short as possible
        //fim do redraw - este bloco pode ser retirado

        //para conferir a opção select MESTRE selecionada
		console.log("Opcao Atual" + OpcaoAtual);
		
		//monta URL completa, com parâmetro
		var url = 'http://' + '@Context.Request.Host/PerguntasBancoGeral/PegaCompetencias/' + OpcaoAtual;
		//verifica url montada
		console.log(url);
		console.log('idConsultoria = ' + $('#SelectConsultoria').val());
        
        //chama AJAX
		$.ajax({
			type: 'GET',
			headers: {
				'Accept': 'application/json',
				'Content-Type': 'text/plain'
			},
			dataType: 'json',
			url: url,
			success: function(data) {
				console.log(data);
				callbackFunction(data); //IMPORTANTE
			}
		});

        //Carrega o select ESCRAVO
		function callbackFunction(resultData) {
			// alert("entrei");
			var items = '<option value="0"><<Selecione uma Competência>></option>';
			//console.log(resultData);
			$.each(resultData, function(i, competencia) {

				items += "<option value='" + competencia.value + "'>" + competencia.text + "</option>";
				$("#SelectCompetencia").append("<option value='" + competencia.value + "'>" + competencia.text + "</option>");
				//confere no console
				console.log("<option value='" + competencia.value + "'>" + competencia.text + "</option>");

			});
			//confere no console
			console.log(items);
			//truque para tirar linha em branco
			$('#SelectCompetencia option:eq(' + 1 + ')').remove(); //retira branco
			
		}
	});

    //função auxiliar REDRAW
    //https://gist.github.com/mgHenry/6154611
	jQuery.fn.redraw = function() {
		jQuery(this).each(function() {
			this.style.display = 'none';
			this.offsetHeight; // no need to store this anywhere, the reference is enough
			this.style.display = 'block';
		});
	};
});

A Ação (Action) no Controlador (Controller)

Montei uma ação específica para o “GET” do Ajax, via Jquery. Antes da ação, defini que para um GET, com [HttpGet]. E também assinalei a política local [EnableCors)”MinhaPolitica”)], já mencionada.

Aqui é montada uma lista simples. Filtrada pela Id do Select mestre, passado via URL como parâmetro. Observe que todos os itens da lista são acrescentados com Selected = false, pois  o Select ESCRAVO ainda não tem nada selecionado (e foi o próprio Javascript que criou o primeiro elemento com “Selecione uma Competência” .

Se isso não tivesse sido feito lá, poderíamos fazer aqui logo depois de definir a nova lista, fazendo um Lista.Add de um único elemento ANTES de entrar no loop foreach.

Observe que o retorno é em formato Json. É isso. Tem muita coisa antiga e errada na internet. Não precisa acrescentar parâmetro nenhum. Funciona que é uma chupeta.

 

 

A A&ccedil;&atilde;o GET no Controlador
//para json
        [HttpGet]
        [EnableCors("MinhaPolitica")]
        public JsonResult PegaCompetencias(int Id)
        {

            List<SelectListItem> Lista = new List<SelectListItem>();
            var Dados = _context.CompetenciasBancoGeral
                    .Where(r => r.IdConsultoria == Id)
                    .OrderBy(r => r.TituloCompetencia)
                    .Select(r => new
                    { r.IdCompetenciaBanco, r.TituloCompetencia });
            foreach (var Linha in Dados)
            {
                Lista.Add(new SelectListItem()
                {
                    Value = Linha.IdCompetenciaBanco.ToString(),
                    Text = Linha.TituloCompetencia,
                    Selected = false
                });
            }
            return Json(Lista);
        }
Configura&ccedil;&otilde;es para Desenvolvimento e Produ&ccedil;&atilde;o
if (env.IsDevelopment())
            {
                 services.AddCors(options =>
                 {
                   options.AddPolicy("MinhaPoliticaLocal",
                    builder => builder.AllowAnyOrigin("localhost")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
                 })
            }
            else
            {
                aservices.AddCors(options =>
                 {
                   options.AddPolicy("MinhaPoliticaRemota",
                    builder => builder.AllowAnyOrigin("meudominio.com.br")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
                 })
            
            }

A View com os selects usando o Select Tag Helper

A view que foi montada tem 3 blocos:

  • Bloco 1: os selects MESTRE e ESCRAVO;
  • Bloco 2: uma seção informativa do resultado da seleção acima se o botão de filtrar é pressionado;
  • Bloco 3: um grid com o resultado da seleção.

DICA:

Habilitando Tag Helpers de forma genérica

Para que tag helpers funcionem em qualquer arquivo de visualização, a opção é habilitar no arquivo auxiliar de visualização que é sempre lido (o _ViewImports.cshtml) .

Assim, no arquivo  _ViewImports.cshtml, inclua:

Isso pode ser feito com outros tag helpers que você vier a construir (além dos padrões Microsoft já existentes no Visual Studio).

Bloco 1 – Selects Mestre e Escravo

cascading selects

O primeiro select é o MESTRE e o segundo é o ESCRAVO. O funcionamento com javascrpt já vimos. Ocorre que quando entramos na página, esses selects devem ser previamente populados.

Papa popular usamos ViewBags, seguindo a sintaxe basica do HTML TAG HELPER para selects:  os dados são carregados dinamicamente a partir de uma base de dados e no select são colocadas no tag asp-items, formato asp-items(“ViewBag.MeusDados)”. Par carregar as ViewBagas é preciso colocar  neles uma lista IEnumerable. A View, nesse ponto, é um simples formulário com dois selects com suas respectivas ViewBags.

C&oacute;digo da View: Formul&aacute;rio (Form) - P&aacute;gina Index.cshtml / Action Index no Controller
<form asp-action="Index2">
    <h2>Filtra Lista de Perguntas por Consultoria e por Competência</h2>
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="IdConsultoria" class="col-md-2 control-label">Consultoria</label>
        <div class="col-md-10">
            <select id="SelectConsultoria" asp-for="IdConsultoria" asp-items="ViewBag.Consultoria" class="form-control seletor"></select>
            <span asp-validation-for="IdConsultoria" class="text-danger"></span>
        </div>
    </div>
    <br /><br />
    <div class="form-group">
        <label asp-for="IdCompetenciaBanco" asp-items="" class="col-md-2 control-label">Competência</label>
        <div class="col-md-10" id="Competencias">
            <select asp-items="ViewBag.Competencia" id="SelectCompetencia" asp-for="IdCompetenciaBanco" class="form-control seletor"></select>
            <span asp-validation-for="IdCompetenciaBanco" class="text-danger"></span>
        </div>
    </div>
    <br /><br />
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10" align="left">
            <table>
                <tbody>
                    <tr>
                        <td><input type="submit" value="Filtra Perguntas" class="btn btn-primary" /> </td>
                        <td> </td>
                        <td><a asp-action="Index" class="btn btn-danger">Limpa Escolhas</a> </td>
                    </tr>
                </tbody>
            </table>
              <br />
        </div>
    </div>
</form>
Note que o form (formulário) é submetido para Index2, no controlador. Index captura a entrada (GET), Index2 captura o formulário quando é submetido (via POST).

Bloco 2 – Botão de Filtrar

O botão Filtra Perguntas, no código acima, é um simples botão de submit, que vai obedecer o encaminhamento para Index2, definida no topo do formulário (<form asp-action=”Index2″>).

O botão Limpa Escolhas é um link simples (<a>…</a>), não passa nenhum parâmetro. A ideia é essa, simplesmente recarregar a página sem nenhuma filtragem, mostrando as 10 últimas perguntas cadastradas sem qualquer filtragem.

cascading dropdown

Quando o botão Filtra Perguntas é clicado, na verdade ele passa para Index2 os dois Ids. Nenhum deles pode estar selecionado, somente um dos dois (ou um ou outro) ou os 2: temos 4 opções possíveis. A ação Index2 simplesmente pega as Ids do POST e “devolve a bola” para a ação Index, que alem de repopular os selects, também muda a mensagem sobre a filtragem e os contadores de Totais (de Consultorias, de Competências e de Perguntas). Além disso, filtra os dados da Grid que vai ser apresentada abaixo desse bloco, no bloco 3. Todas as informações são passadas via ViewBags que são instanciadas na Ação (action) Index do controlador.

O botão Cria Nova Pergunta leva para um formulário de inserção, já com os dois parâmetros escolhidos. Quando uma nova pergunta é gravada, o form (formulário) e perguntas cham novamente a página Index, mas já passando para ela os dois IDs que recebeu (de forma que se pode cadastrar várias perguntas de uma Consultoria, para uma mesma Competência, sem ter de ficar novamente fazendo Selects!!!).

Index.cshtml - Bloco de Informa&ccedil;&otilde;es atrav&eacute;s de ViewBags
<div class="row">
   <div class="col-sm-3">
      <div class="alert-danger" style="position:absolute; position:absolute;top:0;right:0;bottom:0">
         @ViewBag.MensagemAviso
         <span class="glyphicon glyphicon-alert"></span>
      </div>
   </div>
   <div class="col-sm-3">
      <div class="alert-info">
         Total de Consultorias : 
         <h3>@ViewBag.TotalDeConsultorias</h3>
      </div>
   </div>
   <div class="col-sm-3">
      <div class="alert-info">
         Total de Competências : 
         <h3>@ViewBag.TotalDeCompetencias</h3>
      </div>
   </div>
   <div class="col-sm-3">
      <div class="alert-info">
         Total de Perguntas: 
         <h3>@ViewBag.TotalDePerguntas</h3>
      </div>
   </div>
</div>
</div>

Bloco 3 – Grid com  Listagem das últimas perguntas registrado (máximo de 10)

Aqui a coisa pegou, porque o formulário (form) uma um modelo simples (não é uma lista!) e o grid precisa de uma lista… Os arquivos de Views  não permitem, de modo direto, que você defina dois ou mais modelos no topo (cabeçalho). É um modelo somente e ponto. Ir por esse caminho implica em gerar um terceiro modelo que contenha, dentro dele, os modelos que você quer usar na View. Mas pesquisando aqui e ali, acabei descobrindo uma outra forma de fazer isso, que será mostrada mais adiante.

cascading - formulário resultante do dropdown cascading

O modelo das Perguntas é muito simples:

 

Modelo das Perguntas (Model/Perguntas.cs)
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Coaching.Models
{
    public partial class PerguntasBancoGeral
    {
        [Key]
        [Display(Name = "Id da Pergunta do Banco")]
        public int IdPerguntaBanco { get; set; }

        [Required(ErrorMessage = "Favor escolher uma Consultoria.")]
        [Display(Name = "id da Consultoria")]
        public int IdConsultoria { get; set; }

        [Required(ErrorMessage = "Favor escolher uma Competência.")]
        [Display(Name = "Id da Competência do Banco")]
        public int IdCompetenciaBanco { get; set; }

        [Display(Name = "Assertiva Genérica (Hetero)")]
        public string Assertivageral { get; set; }

        [Display(Name = "Assertiva Auto")]
        public string Assertivaauto { get; set; }
    }
}
O modelo acima é definido no topo do arquivo da View:

@model Coaching.Models.PerguntasBancoGeral
@{
ViewData[“Title”] = “Banco de Perguntas – Coaching Adm”;
}

Só que, a Grid, me interessava listar o Nome da Consultoria e o Nome da Competência, que estão em outras tabelas. Montei um modelo FAKE, contendo também os nomes, para poder popular esse modelo “Lista” (IENUMERABLE) através da ação Index do controlador (controller).

E, dentro da View, na hora de LISTAR todas as perguntas, no comando foreach, chamei esse modelo fake com os nomes:
foreach (var item in ViewBag.Lista as IEnumerable<Coaching.Models.PerguntasBancoGeralComNome>)

Veja a seguir o modelo FAKE e o bloco de código HTML da VIew do bloco 3 (grid).

Modelo das Perguntas Na Grid (Model/PerguntasComNomes.cs) - Modelo "FAKE"
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace Coaching.Models
{
    public class PerguntasBancoGeralComNome //somente para visualização
    {
        [Key]
        [Display(Name = "Id da Pergunta do Banco")]
        public int IdPerguntaBanco { get; set; }

        [Display(Name = "id da Consultoria")]
        public int IdConsultoria { get; set; }

        [Display(Name = "Id da Competência do Banco")]
        public int IdCompetenciaBanco { get; set; }

        [Display(Name = "Assertiva Genérica (Hetero)")]
        public string Assertivageral { get; set; }

        [Display(Name = "Assertiva Auto")]
        public string Assertivaauto { get; set; }

        [Display(Name = "Nome da Consultoria")]
        public string NomeConsultoria { get; set; }

        [Display(Name = "Nome da Competência")]
        public string TituloCompetencia { get; set; }
    }
}
HTML da Grid - Bloco 3 - Index.cshtml - Modelo "FAKE" com Nomes (IEnumerable)
<div class="row">
   <div class="col-sm-12">
      <p>
         <a asp-action="Create" asp-route-idConsultoria="@ViewBag.idConsultoria" asp-route-IdCompetenciaBanco="@ViewBag.IdCompetenciaBanco" class="btn btn-primary">Cria Nova Pergunta</a>
      </p>
      <h2>@ViewBag.MensagemTotal</h2>
      @*10 últimas perguntas cadastradas<*@
      <table class="table table-responsive table-hover">
         <thead>
            <tr>
               <th>
                  @Html.DisplayNameFor(model => model.Assertivageral)
               </th>
               <th>
                  @Html.DisplayNameFor(model => model.Assertivaauto)
               </th>
               <th>
                  @*@Html.DisplayNameFor(model => model.IdCompetenciaBanco)*@
                  Id/Competências
               </th>
               <th>
                  Id/Consultoria
               </th>
               <th><b>Ação</b></th>
            </tr>
         </thead>
         <tbody>
            @{
            foreach (var item in ViewBag.Lista as IEnumerable
            <Coaching.Models.PerguntasBancoGeralComNome>
            )
            {
            <tr>
               <td>@item.Assertivageral</td>
               <td>@item.Assertivaauto</td>
               <td>
                  @item.IdCompetenciaBanco/@item.TituloCompetencia
               </td>
               <td>@item.IdConsultoria/@item.NomeConsultoria</td>
               <td>
                  <a asp-action="Edit" asp-route-id="@item.IdPerguntaBanco">Edita</a> |
                  <a asp-action="Details" asp-route-id="@item.IdPerguntaBanco">Detalhes</a> |
                  <a asp-action="Delete" asp-route-id="@item.IdPerguntaBanco">Apaga</a>
               </td>
            </tr>
            }
            }
         </tbody>
      </table>
   </div>
</div>

Populando as opções do Select através do Banco de Dados

Para fazer isso criei dois métodos PRIVADOS dentro do controlador (controller). Um para popular a ViewBag de Consultorias, outro para popular a ViewBag de Competências.

M&eacute;todo Privado para Popular Consultorias - arquivo controlador (controller)
private void PopulateConsultoria(int TipoSelecionado = 0)
        {
            List<SelectListItem> Lista = new List<SelectListItem>();
            if (TipoSelecionado == 0)
            {
                Lista.Add(new SelectListItem()
                { Value = "0", Text = "<<Selecione uma Consultoria>>", Selected = true });
            }
else
                  { Value = "0", Text = "<<Selecione uma Consultoria>>", Selected = false});
            }
            var Dados = _context.Consultorias
                .OrderBy(r => r.NomeConsultoria)
                .Select(r => new
                { r.IdConsultoria, r.NomeConsultoria });
            foreach (var Linha in Dados)
            {
                bool valor = false;
                if (Linha.IdConsultoria == TipoSelecionado)
                {
                    valor = true;
                }
                Lista.Add(new SelectListItem()
                {
                    Value = Linha.IdConsultoria.ToString(),
                    Text = Linha.NomeConsultoria,
                    Selected = valor
                });
            }
            ViewBag.Consultoria = Lista;
        }
Note que o VIewBag é instanciado dentro do método PRIVADO. Outra coisa: atribui o valor zero (0) para o “Selecione uma Consultoria”, pois isso facilita muito saber se a pessoa não fez nenhuma opção no select. É melhor que trabalhar com ”nulls”.

Se houver um item selecionado, vem um valor diferente de zero, que é passado por TipoSelecionado. A linha, em dados, cuja Id “bater” com o valor de TipoSelecionado será marcada como verdadeira (Selected = true).  Assim, quando a ViewBag entregar essa lista para o Select, o mesmo estar´posicionado nesta opção. DO contrário fica na primeira opção (0), “Selecione uma Consultoria”.

Populando as Competências

O princípio desse método é exatamente igual ao do anterior. A diferença é que ele utiliza 2 parâmetros que podem ter 4 comninações possíveis:

  • os 2 não são passados (são zero), nenhum dos dois foi selecionado: mostra todas as opções existentes (todas as competências);
  • somente o Id da Competência foi passado: mostra exatamente essa competência;
  • somente o id da Consultoria foi passado: mostra todas as competências ligadas a essa consultoria
  • os 2 são passados (diferente de zero): mostra exatamente a competência específica (igual caso 2)

O resultado dessa lista é armazenado na ViewBag de Competências dentro do método privado.

M&eacute;todo Privado para Popular Compet&ecirc;ncias - arquivo controlador (controller)
private void PopulateCompetencia(int IdCompetenciaLida = 0, int idConsultoriaLido = 0)
        {
            List<SelectListItem> Lista = new List<SelectListItem>();
            var Comp = 0;
            var Cons = 0;
            if (IdCompetenciaLida >= 1)
            {
                Comp = 1;
            }
            if (idConsultoriaLido >= 1)
            {
                Cons = 1;
            }
            if (IdCompetenciaLida == 0)
            {
                Lista.Add(new SelectListItem()
                { Value = "0", Text = "<<Selecione uma Competência>>", Selected = true });
            }
            var Dados = (from i in _context.CompetenciasBancoGeral
                             //join k in _context.Consultorias on i.IdConsultoria equals k.IdConsultoria
                         where (Cons == 1 && i.IdConsultoria == idConsultoriaLido) || (Comp == 1 && i.IdCompetenciaBanco == IdCompetenciaLida)
                         || (Comp == 0 && Cons == 0)
                         select new CompetenciasBancoGeral
                         {
                             IdCompetenciaBanco = i.IdCompetenciaBanco,
                             TituloCompetencia = i.TituloCompetencia
                         })
                         .OrderBy(p => p.TituloCompetencia)
                         .ToList();
            foreach (var Linha in Dados)
            {
                bool valor = false;
                if (Linha.IdCompetenciaBanco == IdCompetenciaLida)
                {
                    valor = true;
                }
                Lista.Add(new SelectListItem()
                {
                    Value = Linha.IdCompetenciaBanco.ToString(),
                    Text = Linha.TituloCompetencia,
                    Selected = valor
                });
            }
            ViewBag.Competencia = Lista;
        }

A Ação (Action) Index do Controlador

Esta ação é o “coração” desta pequena aplicação. Quando se entra na pagina Index.cshtml, a ação Index é solicitada no controlador (controller) e ela executa 3 papéis importantes:

  • chama os dois métodos populadores, passando a eles os parâmetros escolhidos na View;
  • carrega uma lista para a grid do modelo fake, com as devidas filtragens dos parâmetros e a coloca também numa VIeBag;
  • calcula e define todas as demais ViewBags que serão mostradas no arquivo de visualização (View), considerando as 4 possíveis alternativas de passagem dos 2 parâmetros.

O código é mostrado a seguir.

C&oacute;digo da A&ccedil;&atilde;o Index do Controlador (controller)
        // GET: PerguntasBancoGeral
        public async Task<IActionResult> Index(int idConsultoria = 0, int IdCompetenciaBanco = 0)
        {
            //id1 -id Consultoria
            //id2 - id Competencia
            var id1 = 0;
            var id2 = 0;
            var pConsultoria = 0;
            var pCompetencia = 0;
            if (idConsultoria >= 1)
            {
                id1 = 1;
                pConsultoria = idConsultoria;
            }
            if (IdCompetenciaBanco >= 1)
            {
                id2 = 1;
                pCompetencia = IdCompetenciaBanco;
            }
            PopulateConsultoria(pConsultoria);
            PopulateCompetencia(pCompetencia, pConsultoria);
            ViewBag.Lista = await (from i in _context.PerguntasBancoGeral
                                   join k in _context.Consultorias on i.IdConsultoria equals k.IdConsultoria
                                   join m in _context.CompetenciasBancoGeral on i.IdCompetenciaBanco equals m.IdCompetenciaBanco
                                   where (
                                   (id1 == 0 && id2 == 0)
                                   ||
                                   (id1 == 0 && id2 == 1 && i.IdCompetenciaBanco == pCompetencia)
                                   ||
                                   (id1 == 1 && id2 == 0 && i.IdConsultoria == pConsultoria)
                                   ||
                                   (id1 == 1 && id2 == 1 && i.IdConsultoria == pConsultoria && i.IdCompetenciaBanco == pCompetencia)
                                   )
                                   select new PerguntasBancoGeralComNome
                                   {
                                       Assertivaauto = i.Assertivaauto,
                                       Assertivageral = i.Assertivageral,
                                       IdCompetenciaBanco = i.IdCompetenciaBanco,
                                       IdPerguntaBanco = i.IdPerguntaBanco,
                                       IdConsultoria = k.IdConsultoria,
                                       NomeConsultoria = k.NomeConsultoria,
                                       TituloCompetencia = m.TituloCompetencia
                                   })
                                   .OrderByDescending(p => p.IdPerguntaBanco)
                                   .Take(10) //pega as 10 últimas
                                   .ToListAsync();
            if (pConsultoria == 0 && pCompetencia == 0)
            {
                ViewBag.MensagemAviso = "Ainda sem filtragem";
                ViewBag.TotalDeConsultorias = await _context.Consultorias.CountAsync();
                ViewBag.TotalDeCompetencias = await _context.CompetenciasBancoGeral.CountAsync();
                ViewBag.TotalDePerguntas = await _context.PerguntasBancoGeral.CountAsync();
               
            }
            else if (pConsultoria >= 1 && pCompetencia == 0)
            {
                ViewBag.MensagemAviso = "Consultoria Definida";
                ViewBag.TotalDeConsultorias = await _context.Consultorias.Where(x => x.IdConsultoria == pConsultoria).CountAsync();
                ViewBag.TotalDeCompetencias = await _context.CompetenciasBancoGeral.Where(x => x.IdConsultoria == pConsultoria).CountAsync();
                ViewBag.TotalDePerguntas = await _context.PerguntasBancoGeral.Where(x => x.IdConsultoria == pConsultoria).CountAsync();
            }
            else if (pConsultoria >= 1 && pCompetencia >= 1)
            {
                ViewBag.MensagemAviso = "Consultoria Definida e Competência Definida: Clique em CRIA NOVA PERGUNTA";
                ViewBag.TotalDeConsultorias = await _context.Consultorias.Where(x => x.IdConsultoria == pConsultoria).CountAsync();
                ViewBag.TotalDeCompetencias = await _context.CompetenciasBancoGeral.Where(x => x.IdConsultoria == pConsultoria && x.IdCompetenciaBanco == pCompetencia).CountAsync();
                ViewBag.TotalDePerguntas = await _context.PerguntasBancoGeral.Where(x => x.IdConsultoria == pConsultoria && x.IdCompetenciaBanco == pCompetencia).CountAsync();
            }
            else // else if (pConsultoria = 0 1 && pCompetencia >= 1)
            {
                ViewBag.MensagemAviso = "Competência Definida: falta definir consultoria";
                ViewBag.TotalDeConsultorias = await _context.Consultorias.CountAsync();
                ViewBag.TotalDeCompetencias = await _context.CompetenciasBancoGeral.Where(x => x.IdCompetenciaBanco == pCompetencia).CountAsync();
                ViewBag.TotalDePerguntas = await _context.PerguntasBancoGeral.Where(x => x.IdCompetenciaBanco == pCompetencia).CountAsync();
            }
            if (ViewBag.TotalDePerguntas >= 10) { ViewBag.MensagemTotal = "10 últimas perguntas cadastradas"; }
            else if (ViewBag.TotalDePerguntas >= 1 && ViewBag.TotalDePerguntas <= 9) { ViewBag.MensagemTotal = Convert.ToString(ViewBag.TotalDePerguntas) + " últimas perguntas cadastradas"; }
            else { ViewBag.MensagemTotal = "Nenhuma pergunta cadastrada ainda (nesta filtragem)"; }
            ViewBag.idConsultoria = idConsultoria;
            ViewBag.IdCompetenciaBanco = IdCompetenciaBanco;
            return View();
        }

Obrigado pela sua leitura. Continue visitando este blog e compartilhe artigos em sua rede de relacionamento. Por favor, se quiser, registre sugestões e comentários ao final da página.