<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Design e Front-End &#8211; Velho Bit</title>
	<atom:link href="https://velhobit.com.br/design-e-front-end/feed" rel="self" type="application/rss+xml" />
	<link>https://velhobit.com.br</link>
	<description>Artigos, Notícias e Tutoriais sobre Web Design, Design Gráfico, Desenvolvimento e Programação Web... e um tico de games</description>
	<lastBuildDate>Thu, 19 Feb 2026 17:55:45 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://velhobit.com.br/wp-content/uploads/2024/10/cropped-minieu-32x32.png</url>
	<title>Design e Front-End &#8211; Velho Bit</title>
	<link>https://velhobit.com.br</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Como Resolver o Erro de Locale no Angular 20 com Native Federation</title>
		<link>https://velhobit.com.br/design-e-front-end/como-resolver-o-erro-de-locale-no-angular-20-com-native-federation.html</link>
		
		<dc:creator><![CDATA[Rodrigo Portillo]]></dc:creator>
		<pubDate>Thu, 19 Feb 2026 17:52:03 +0000</pubDate>
				<category><![CDATA[Design e Front-End]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[programação]]></category>
		<guid isPermaLink="false">https://velhobit.com.br/?p=5461</guid>

					<description><![CDATA[Se você já tentou usar&#160;Angular 20&#160;com&#160;Native Module Federation&#160;e se deparou com erros do tipo: ou você sabe o quanto isso pode ser frustrante. Esse problema acontece devido a uma mudança significativa entre o Angular 19 e o 20 em como o&#160;Native Federation&#160;lida com locales e I18N. Por que isso acontece só no Angular 20 No&#160;Angular [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Se você já tentou usar&nbsp;<strong>Angular 20</strong>&nbsp;com&nbsp;<strong>Native Module Federation</strong>&nbsp;e se deparou com erros do tipo:</p>



<pre class="wp-block-code"><code><strong>Unable to resolve specifier '@angular/common/locales/pt'</strong></code></pre>



<p>ou</p>



<pre class="wp-block-code"><code><strong>NG0701: Missing locale data for the locale "pt-BR"</strong></code></pre>



<p>você sabe o quanto isso pode ser frustrante. Esse problema acontece devido a uma mudança significativa entre o Angular 19 e o 20 em como o&nbsp;<strong>Native Federation</strong>&nbsp;lida com locales e I18N.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Por que isso acontece só no Angular 20</h2>



<p>No&nbsp;<strong>Angular 19</strong>, o Native Federation não tinha suporte nativo para I18N, então o carregamento de arquivos de locale precisava ser feito manualmente, usando helpers como&nbsp;<code>shareAngularLocales</code>&nbsp;com a flag&nbsp;<code>legacy: true</code>. Qualquer import de&nbsp;<code>@angular/common/locales/*</code>&nbsp;nos remotes geralmente passava despercebido, mesmo que estivesse bundlado de forma não ideal.</p>



<p>A partir do&nbsp;<strong>Angular 20.0.6</strong>, o Native Federation mudou o comportamento:</p>



<ul class="wp-block-list">
<li><strong>Suporte nativo a I18N:</strong>&nbsp;agora os remotes podem carregar arquivos de locale automaticamente.</li>



<li><strong><code>ignoreUnusedDeps</code>&nbsp;ativado:</strong>&nbsp;quando esta feature está ligada, o builder ignora dependências não usadas, o que evita que o esbuild tente transformar imports de locales (<code>@angular/common/locales/pt</code>) em módulos remotos via HTTP, eliminando o clássico erro&nbsp;<code>Unable to resolve specifier</code>.</li>



<li><strong>Por isso o problema só aparece agora:</strong>&nbsp;se você migrou de Angular 19 para 20 e ainda não ativou&nbsp;<code>ignoreUnusedDeps</code>, qualquer import de locale direto no remote explode, mesmo que você registre o locale no host.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Fonte oficial:&nbsp;<a href="https://github.com/angular-architects/module-federation-plugin/blob/main/libs/native-federation/README.md">Native Federation README &#8211; Angular I18N</a></p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">A Solução Definitiva</h2>



<p>A solução é&nbsp;<strong>configurar o Native Federation corretamente</strong>&nbsp;e usar o helper&nbsp;<code>shareAngularLocales</code>&nbsp;para tornar os bundles compatíveis, sem precisar importar os arquivos de locale diretamente no remote.</p>



<h3 class="wp-block-heading"><code>federation.config.js</code>&nbsp;do Remote</h3>


<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="javascript" name="mshighlighter" >const { withNativeFederation, shareAll, shareAngularLocales } = require('@angular-architects/native-federation/config');

const shareConfig = {
  singleton: true,
  strictVersion: true,
  requiredVersion: 'auto',
  includeSecondaries: true
};

module.exports = withNativeFederation({
  name: 'core',
  
  // Ignora o próprio arquivo de configuração e checagem agressiva de dependências
  ignorePatterns: ['federation.config.js'],
  features: {
    ignoreUnusedDeps: true
  },

  shared: {
    ...shareAll(shareConfig),

    // Garante que os locales do Angular fiquem bundle-friendly
    ...shareAngularLocales(['pt'])
  }
});</textarea></pre>
</div>



<h3 class="wp-block-heading">Por que isso funciona</h3>



<ol class="wp-block-list">
<li><strong><code>ignorePatterns: ['federation.config.js']</code></strong>&nbsp;faz o builder ignorar o próprio arquivo de configuração, evitando que ele tente federar imports internos como os de locale.</li>



<li><strong><code>features: { ignoreUnusedDeps: true }</code></strong>&nbsp;evita que o esbuild transforme imports de locales em HTTP, eliminando o erro&nbsp;<code>Unable to resolve specifier</code>.</li>



<li><strong><code>shareAngularLocales(['pt'])</code></strong>&nbsp;prepara o bundle do remote para usar os arquivos de locale corretamente, sem precisar de imports diretos.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Registro do Locale no Host</h3>



<p>Mesmo com&nbsp;<code>shareAngularLocales</code>, os pipes do Angular (<code>DatePipe</code>,&nbsp;<code>CurrencyPipe</code>,&nbsp;<code>DecimalPipe</code>) precisam de&nbsp;<strong>registro no host</strong>:</p>



<pre class="wp-block-code"><code>import { registerLocaleData } from '@angular/common';
import localePt from '@angular/common/locales/pt';

registerLocaleData(localePt, 'pt-BR');
</code></pre>



<ul class="wp-block-list">
<li>Isso garante que o locale&nbsp;<code>pt-BR</code>&nbsp;esteja disponível para todos os remotes.</li>



<li>Nenhum remote deve importar ou registrar arquivos de locale diretamente.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Com o Angular 20 e Native Federation, o gerenciamento de I18N mudou. O problema de&nbsp;<code>Unable to resolve specifier '@angular/common/locales/pt'</code>&nbsp;aparece apenas porque o esbuild tenta transformar imports de Node_modules em ESM remoto. A solução combina:</p>



<ul class="wp-block-list">
<li><strong>shareAngularLocales</strong>&nbsp;no remote</li>



<li><strong>ignoreUnusedDeps</strong>&nbsp;no remote</li>



<li><strong>registro do locale no host</strong></li>
</ul>



<p>Seguindo essas etapas, seu app vai rodar com&nbsp;<code>pt-BR</code>&nbsp;corretamente, sem travar o bundle, e compatível com os novos padrões do Angular 20.</p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Como centralizar verticalmente elementos HTML com CSS</title>
		<link>https://velhobit.com.br/tutoriais/como-centralizar-verticalmente-elementos-html-com-css-2.html</link>
		
		<dc:creator><![CDATA[Rodrigo Portillo]]></dc:creator>
		<pubDate>Wed, 02 Jun 2021 15:55:00 +0000</pubDate>
				<category><![CDATA[Design e Front-End]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[front-end]]></category>
		<guid isPermaLink="false">https://site.velhobit.com.br/?p=79</guid>

					<description><![CDATA[Uma das coisas mais comuns, mas ao mesmo tempo mais chatas de se fazer no CSS é alinhar verticalmente elementos em tela. Existem várias formas de fazer isso. Neste post, vou elencar as minhas formas favoritas de fazer isso. Alinhamento com Flexbox Flex é uma propriedade incrível do CSS que permite organizar elementos. Se outrora [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p id="block-6649b4be-5663-4f89-88e0-637dda1ae9f9">Uma das coisas mais comuns, mas ao mesmo tempo mais chatas de se fazer no CSS é alinhar verticalmente elementos em tela. Existem várias formas de fazer isso. Neste post, vou elencar as minhas formas favoritas de fazer isso.</p>



<h2 class="wp-block-heading" id="block-044e5df1-377f-4af3-9fca-89873d318cc9">Alinhamento com Flexbox</h2>



<p id="block-76c3e40b-7e0a-4b6f-96fc-b607806b82e5">Flex é uma propriedade incrível do CSS que permite organizar elementos. Se outrora tínhamos que fazer inúmeras gambiarras com float, o flex nos permite controlar o comportamentos dos filhos de um container. Para centralizar verticalmente um objeto, podemos usar a direção de coluna, em seu container pai.</p>



<script async src="//jsfiddle.net/velhobit/q1xsybp9/embed/result,html,css/"></script>



<h2 class="wp-block-heading" id="block-67d6f3aa-0db2-4282-af69-76386eb87f4e">Alinhamento com position</h2>



<p id="block-2ea4513d-94ab-48e7-852d-60717d06ce04">Com um pouco de matemática, conseguimos fazer um alinhamento vertical com o position absolute. Porém, é importante lembrar que o objeto será flutuante e que seu pai, necessariamente, precisa ser um position relative. O problema de usar esse tipo de alinhamento é que o conteúdo da posição precisa ser fixo. Felizmente, hoje, conseguimos fazer cálculos com variáveis de CSS, o que facilita a forma de implementarmos essa técnica. A vantagem dessa técnica é poder usar, justamente, em ambientes flutuantes que se sobreponham. Porém, caso você não precise que ele se alinhe ao pai, mas à viewport, você pode usar também o position como fixed.</p>



<iframe width="100%" height="500" src="//jsfiddle.net/velhobit/qd8fn6r9/1/embedded/result,html,css/" allowfullscreen="allowfullscreen" allowpaymentrequest frameborder="0"></iframe>



<h2 class="wp-block-heading" id="block-d8b5915e-f1e6-40f7-bcda-b1d4c3c87e33">Alinhamento com Grid</h2>



<p id="block-34c78db0-4bd9-4bf3-90ab-6be7cd1f11b2">Outra forma moderna de alinhar verticalmente é através do uso de grids. A vantagem de usar grids é que o tamanho do conteúdo do elemento alinhado corresponderá ao tamanho da grid que se deseja utilizar. Ou seja, é adaptável de acordo com a viewport, e não referente ao seu conteúdo. Para isso, basta definirmos a quantidade de colunas e linhas que desejamos e estabelecemos onde o objeto alinhado vai iniciar e terminar.</p>



<iframe width="100%" height="400" src="//jsfiddle.net/velhobit/r869swqz/embedded/result,html,css/" allowfullscreen="allowfullscreen" allowpaymentrequest frameborder="0"></iframe>



<h2 class="wp-block-heading" id="block-524d9cba-b523-427b-a79e-c81a23ce8c7e">Exemplo de uso (Modal Alinhado ao Centro)</h2>



<p id="block-fb03f0a5-9a2b-4fc8-a6c4-648568030b0c">Para mostrar como pode ser usado os alinhamentos, que tal criarmos um simples modal alinhado ao centro da tela?</p>



<p id="block-46b25bbb-6bf5-445d-a3d2-281f12147810">Um modal é composto por uma cortina que reveste o conteúdo original, seguido de um painel com alguma informação dentro. É convenção de que os modals carreguem essas informações no centro da tela, afim de que a informação fique direcionada e encapsulada, levando, assim, o usuário à uma atenção maior àquela informação. Ou seja, isolar e destacar. O exemplo abaixo foi feito usando a primeira estratégia de alinhamento vertical aqui apresentada, pois, desta forma, o tamanho do modal que vai ser a referência para a centralização. Alguns efeitos foram adicionados para ilustrar melhor.</p>



<iframe width="100%" height="500" src="//jsfiddle.net/velhobit/pbgmvu2x/embedded/result,css,html,js/" allowfullscreen="allowfullscreen" allowpaymentrequest frameborder="0"></iframe>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Como adicionar e remover dinamicamente campos HTML em um form? (Javascript puro)</title>
		<link>https://velhobit.com.br/tutoriais/como-adicionar-e-remover-dinamicamente-campos-html-em-um-form-javascript-puro.html</link>
		
		<dc:creator><![CDATA[Rodrigo Portillo]]></dc:creator>
		<pubDate>Sun, 14 Feb 2021 16:04:00 +0000</pubDate>
				<category><![CDATA[Design e Front-End]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[estilo]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[frontend]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[javascrip]]></category>
		<category><![CDATA[jsvanilla]]></category>
		<guid isPermaLink="false">https://site.velhobit.com.br/?p=82</guid>

					<description><![CDATA[O Javascript nos permite criar conteúdos dinâmicos e podemos usar isso para adicionar remover e adicionar elementos de acordo com as opções do usuário. Dados como informações sobre dependentes, links de mídias sociais, e-mails adicionais, etc. são curtos e não fazem sentido criarmos um formulário separado apenas para estes. Por isso, é interessante incluirmos a [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p id="block-e8021681-0362-4698-bab1-e06ce8fcdc26">O Javascript nos permite criar conteúdos dinâmicos e podemos usar isso para adicionar remover e adicionar elementos de acordo com as opções do usuário. Dados como informações sobre dependentes, links de mídias sociais, e-mails adicionais, etc. são curtos e não fazem sentido criarmos um formulário separado apenas para estes. Por isso, é interessante incluirmos a opção de adicionar diretamente esses campos em um subformulário dinâmico.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p id="block-7b013644-fd16-427f-ad7f-0dac65241e16">Obs. Se quiser ir direto para o código final, procure o link do JsFiddle no final do post.</p>
</blockquote>



<h2 class="wp-block-heading" id="block-50427a97-6435-4fe2-b0db-0ab0a0900e76">HTML</h2>



<p id="block-38a0b969-940d-488c-97fd-4070c90e2c76">Para iniciarmos, basta criar um container no HTML onde você quer que os elementos sejam exibidos, além do botão simples de adição e um botão de captura de dados, para que, desta forma, possamos enviar o JSON resultante para o back-end.</p>



<p id="block-0cea6af6-c9bb-4ce3-8f87-10fcfb3593bf">A organização dos containers é sempre muito importante quando trabalhamos com Javascript e nos dedicamos ao uso correto da web semântica.</p>



<pre class="wp-block-code"><code>&lt;div class="dependentes">
  &lt;button id="btnAdicionarDependentes">
  &#x1f4dd;Adicionar Dependentes
  &lt;/button>
  &lt;div class="container" id="dependentesContainer">
  &lt;/div>
  &lt;button class="green" id="btnCapturarDados">
  &#x2705; Capturar Dados
  &lt;/button>
&lt;/div>
&lt;pre id="containerDados">  
&lt;/pre></code></pre>



<h2 class="wp-block-heading" id="block-79778471-435b-4794-a208-bf0e3f8ac0df">Javascript</h2>



<p id="block-740ad472-30ad-4f46-84c9-50f7fcb0c77c">Como de praxe, usaremos o Javascript puro para realizar essa tarefa, dessa forma você poderá usar em qualquer lugar o que aprender aqui.</p>



<p id="block-8418b415-53dc-42c7-8343-a447bc7bc2c4">Para poder capturar e devolver os dados, usaremos um objeto JSON, dessa forma fica fácil remontar, tanto no <em>back-end</em>, quando no <em>front-end</em>, os dados nas formatações e/ou elementos que precisamos.</p>



<p id="block-5e272e83-5318-45b2-832b-693f35e68ee3">Vamos criar, como exemplo, o JSON abaixo, e vamos declará-lo em uma variável global chamada dependentes, seguindo a ideia de um cadastro de lista de dependentes, então temos:</p>



<pre class="wp-block-code"><code>var dependentes = &#91;{
  identificador: 13,
  nome: "Joana da Silva",
  idade: 12,
}];</code></pre>



<p id="block-9661ff72-c21f-4444-939c-6b7f24254659">Agora vamos nos focar nas funções. A primeira coisa que vamos fazer é criar um método que pegue os dados do JSON e o converta para elementos HTML renderizados na tela. Dessa forma, usaremos um laço para ler o JSON e aplicamos seus dados em uma <em>template string</em> e o adicionamos no container específico:</p>



<pre class="wp-block-code"><code>function carregarDependentes() {
  let dependentes_container = document.querySelector("#dependentesContainer");
  dependentes_container.innerHTML = "";
  dependentes.forEach((el) =&amp;gt; {
    let identificador = el.identificador;
    let nome = el.nome;
    let idade = el.idade;
    let dependente_container = `&lt;div class="dependente" data-id="${identificador}">
    								&lt;input class="nome" placeholder="Digite o nome" type="text" value="${nome}">
                                    &lt;input class="idade" placeholder="Digite a idade" type="number" value="${idade}">
                                    &lt;div class="action">
                                        &lt;a href="#" class="salvar">salvar &#x1f4be;&lt;/a>
                                        &lt;a href="#" class="remover">&#x274c;&lt;/a>
									&lt;/div>
                                &lt;/div>`;
    dependentes_container.innerHTML += dependente_container;
  });
}</code></pre>



<p id="block-e3a01ded-6e1f-4742-968c-475a44d36414">Agora vem o segredo que facilita o processo e o deixa mais organizado. Ao invés de remover e adicionar os elementos na tela, iremos nos focar em remover e adicionar do JSON e, em seguida, regenerar os elementos a partir desse objeto. Ficando, assim, com um código mais limpo. Outro motivo pelo qual usamos a regeneração dos elementos é para evitar criarmos IDs únicos temporários. Ao regenerar, podemos usar os índices do próprio <em>array </em>como identificador.</p>



<p id="block-ff072f21-a361-4bf0-8520-f4ad84f120a7">Para adicionar um novo item, basta incluirmos um dado vazio no JSON, porém, seguindo nosso modelo, e mandamos gerar novamente os elementos:</p>



<pre class="wp-block-code"><code>function adicionarDependentes() {
  dependentes.push({ identificador: "", nome: "", idade: "" });
  carregarDependentes();
}</code></pre>



<p id="block-2639192c-d7f1-45ad-a887-05818f80f05a">Para remover, similar a criação de um novo, vamos usar um laço, porém para adicionar o evento aos botões de excluir. Usaremos então o método <em>splice </em>para remover o <em>array</em>. Depois, obviamente, vamos regenerar os elementos a partir da função carregarDependentes():</p>



<pre class="wp-block-code"><code>function removerDependentes() {
  document
    .querySelectorAll("#dependentesContainer .remover")
    .forEach((el, i) =&amp;gt; {
      el.addEventListener("click", () =&amp;gt; {
        dependentes.splice(i, 1); // O splice vai remover um item do array no JSON
        carregarDependentes(); // E chamamos o método para regenerar os elementos
      });
    });
}</code></pre>



<p id="block-f9a40aa0-2a1e-4949-a1be-e25e8d278dd2">Uma vez que adicionamos uma nova linha em branco precisamos salvar seu preenchimento e aí iremos usar a mesma lógica de remoção, mas usaremos o <em>splice </em>para substituir e não para remover um dado do JSON. Porém, adicionaremos uma pequena validação para evitar entrar dados incompletos:</p>



<pre class="wp-block-code"><code>unction salvarDependentes() {
  document
    .querySelectorAll("#dependentesContainer .salvar")
    .forEach((el, i) =&amp;gt; {
      el.addEventListener("click", () =&amp;gt; {
        let identificador = el.parentElement.parentElement.getAttribute(
          "data-id"
        );
        let nome = el.parentElement.parentElement.querySelector(".nome").value;
        let idade = el.parentElement.parentElement.querySelector(".idade")
          .value;

        if (!nome.length || !idade.length) { // Verifica se nome e idade foram preenchidos
          alert("Nome e idade precisam ser preenchidos para salvar.");
          return false;
        }
        dependentes.splice(i, 1, {
          identificador: identificador,
          nome: nome,
          idade: idade,
        }); // Substitui o dado no JSON
        carregarDependentes(); //  E chamamos o método para regenerar os elementos
      });
    });
}</code></pre>



<p id="block-5febd00c-a838-48a5-a8a6-ea01d4d76e6a">Um outro método que precisamos adicionar é uma forma de <strong>bloquear </strong>para que um usuário consiga clicar em outros elementos ao redor, sem antes finalizar a edição do item. Para isso, iremos fazer um laço que adiciona uma classe de CSS, que vamos chamar de <em>disabled</em>, em todos os elementos, exceto o que está sendo editado. Essa classe possui um <strong><em>point-events: 0</em></strong> e um <strong><em>opacity: 0.5</em></strong>. Para demonstrar que está desativado, você pode ainda adicionar outros efeitos, como filtros de baixo contraste ou escala de cinza.</p>



<pre class="wp-block-code"><code>function travarOutros(element) {
  if (element == false) { // Passar false como parâmetro para que todos os elementos fiquem habilitados novamente, ao invés de apenas o elemento que queremos liberar
    document
      .querySelectorAll(".dependentes button, .dependentes .container &amp;gt; div")
      .forEach((el) =&amp;gt; {
        el.classList.remove("disabled");
      });
    document.querySelector("#containerDados").innerHTML = "";
    return false;
  }
  document
    .querySelectorAll(".dependentes button, .dependentes .container &amp;gt; div")
    .forEach((el) =&amp;gt; {
      if (el != element) {  // Verifica se o elemento no laço é o que está sendo editado
        el.classList.add("disabled");
      }
    });
}</code></pre>



<p id="block-be0547a1-dea2-4448-8a5e-9514278a94d4">Agora, antes de continuarmos, vamos revisitar as funções acima para chamar, quando necessário, uma função dentro da outra (leia os comentários no código para entender), ficando assim:</p>



<pre class="wp-block-code"><code>function carregarDependentes() {
  let dependentes_container = document.querySelector("#dependentesContainer");
  dependentes_container.innerHTML = "";
  dependentes.forEach((el) =&amp;gt; {
    let identificador = el.identificador;
    let nome = el.nome;
    let idade = el.idade;
    let dependente_container = `&lt;div class="dependente" data-id="${identificador}">
    															&lt;input class="nome" placeholder="Digite o nome" type="text" value="${nome}">
                                  &lt;input class="idade" placeholder="Digite a idade" type="number" value="${idade}">
                                  &lt;div class="action">
                                  	&lt;a href="#" class="salvar">salvar &#x1f4be;&lt;/a>
                                    &lt;a href="#" class="remover">&#x274c;&lt;/a>
																	&lt;/div>
															  &lt;/div>`;
    dependentes_container.innerHTML += dependente_container;
  });
  salvarDependentes(); // Adicionamos o método aqui para que o laço seja aplicado nos novos items adicionados
  removerDependentes(); // Adicionamos o método aqui para que o laço seja aplicado nos novos items adicionados
  travarOutros(false); // Adicionamos para destravar tudo
}

function removerDependentes() {
  document
    .querySelectorAll("#dependentesContainer .remover")
    .forEach((el, i) =&amp;gt; {
      el.addEventListener("click", () =&amp;gt; {
        dependentes.splice(i, 1);
        carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
      });
    });
}

function adicionarDependentes() {
  dependentes.push({ identificador: "", nome: "", idade: "" });
  carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
  travarOutros(
    document.querySelector("#dependentesContainer &amp;gt; div:last-child")
  ); // Desabilitar todos os outros elementos, exceto o que acabou de ser adicionado
}

function salvarDependentes() {
  document
    .querySelectorAll("#dependentesContainer .salvar")
    .forEach((el, i) =&amp;gt; {
      el.addEventListener("click", () =&amp;gt; {
        let identificador = el.parentElement.parentElement.getAttribute(
          "data-id"
        );
        let nome = el.parentElement.parentElement.querySelector(".nome").value;
        let idade = el.parentElement.parentElement.querySelector(".idade")
          .value;

        if (!nome.length || !idade.length) {
          alert("Nome e idade precisam ser preenchidos para salvar.");
          return false;
        }
        dependentes.splice(i, 1, {
          identificador: identificador,
          nome: nome,
          idade: idade,
        });
        carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
        travarOutros(false); // Liberar todos os elementos novamente
      });
    });
}

function travarOutros(element) {
  if (element == false) {
    document
      .querySelectorAll(".dependentes button, .dependentes .container &amp;gt; div")
      .forEach((el) =&amp;gt; {
        el.classList.remove("disabled");
      });
    document.querySelector("#containerDados").innerHTML = "";
    return false;
  }
  document
    .querySelectorAll(".dependentes button, .dependentes .container &amp;gt; div")
    .forEach((el) =&amp;gt; {
      if (el != element) {
        el.classList.add("disabled");
      }
    });
}</code></pre>



<p id="block-ab9c8db0-380f-4d31-b0a5-d84dda993870">Agora, tudo o que precisamos fazer é incluir os comandos de inicialização, onde aplicamos o método de adição ao evento de clique do botão e carregamos os dados iniciais do JSON:</p>



<pre class="wp-block-code"><code>//init
document.querySelector("#btnAdicionarDependentes").addEventListener("click", adicionarDependentes);
carregarDependentes();</code></pre>



<p id="block-d689a75a-a671-4218-878b-1e4b41b1034a">Por fim, vamos criar uma função para o botão de capturar dados apenas para extrair e mostrar os dados em JSON. Você pode, eventualmente, usar esses dados e enviar via POST, por AJAX ou via campo oculto, e pegar no back-end para guardar ou processar os dados (como com um json_decoder, do PHP):</p>



<pre class="wp-block-code"><code>//capturarDados
document.querySelector("#btnCapturarDados").addEventListener("click", ()=&amp;gt;{
	document.querySelector("#containerDados").innerHTML = JSON.stringify(dependentes, undefined, 4);
});</code></pre>



<h2 class="wp-block-heading" id="block-525d96fb-9ba9-40d1-b78e-867b44f386a7">CSS</h2>



<p id="block-1ed39d06-f9d5-405c-8d18-47bec57b5d66">O único CSS que precisaremos usar é para aplicar a classe <em>disabled</em>. Se por acaso você está usando algum <em>framework </em>CSS, recomendo que você use o relativo a esta classe deste. Consulte a documentação, onde geralmente está relacionado aos <em>helpers</em>:</p>



<pre class="wp-block-code"><code>.disabled{
  pointer-events: none;
  opacity: .5;
}</code></pre>



<p id="block-6f8b1d9a-075f-4ca6-9508-3128557d4d10">Se você quer usar o CSS mais elaborado que usei aqui, veja abaixo o link do JsFiddle.</p>



<h2 class="wp-block-heading" id="block-fa6cb5c7-c024-4cd6-bca2-b05c15a5988f">Finalizando</h2>



<p id="block-dc6ff86e-45f8-4824-a83a-c908fcc3dca2">Criar formulários dinâmicos auxilia a usabilidade à medida que permite que o usuário adicione dados de forma mais rápida e com respostas visuais imediatas. O uso aqui do Javascript puro visa a facilidade para que você possa implementar em quaisquer projetos, incluindo os com Typescript. Trabalhe um pouco no código para adequá-lo à sua necessidade. E, como sempre, você poderá puxar o código e testar direto do JsFiddle.</p>



<p id="block-5f910d6b-c133-434b-be75-bfeb33999629">Aproveite e entre para nosso grupo de discussão no <a href="https://t.me/designprogramacao" target="_blank" rel="noreferrer noopener">Telegram</a>.</p>



<script async="" src="//jsfiddle.net/velhobit/mwh8f2o1/embed/"></script>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
