{"id":"repo/faq-drag-drop","source":"repo","sourceLabel":"repository root","sourcePath":"FAQ_DRAG_DROP.md","routePath":"/fastapp/public-docs/page/repo/faq-drag-drop","rawPath":"/fastapp/public-docs/raw/repo/faq-drag-drop","slug":["repo","faq-drag-drop"],"slugPath":"repo/faq-drag-drop","title":"FAQ Reordenação Drag & Drop (Perguntas Frequentes)","description":"R : Adicione a prop sortable=\"true\" ao DynamicList:","headings":["FAQ Reordenação Drag & Drop (Perguntas Frequentes)","❓ Perguntas sobre Funcionalidade","P: Como ativo a reordenação no meu componente?","P: Qual é a diferença entre DynamicList e PropertyListEditor?","P: O que é o \"drag handle\"?","P: Preciso atualizar a API quando reordenar?","P: Como funciona a sincronização com o estado \"dirty\"?","P: Posso reordenar dentro de um grupo específico?","P: O que acontece se o usuário sair sem salvar?","❓ Perguntas sobre UI/UX","P: Como faço o handle aparecer apenas ao passar o mouse?","P: Posso customizar o ícone do handle?","P: Qual é a cor durante o arraste?","P: Posso mudar a duração da animação?","P: Como funciona no mobile?","❓ Perguntas sobre Dados","P: Os dados são salvos automaticamente ao reordenar?","P: Como garanto que a ordem é única?","P: E se duas propriedades tiverem o mesmo nome?","P: Como desfaço uma reordenação?","P: Posso reordenar entre múltiplas listas?","❓ Perguntas sobre Performance","P: Qual é o limite de propriedades que posso reordenar?","P: Há lag ao arrastar muitos itens?"],"wordCount":917,"markdown":"# FAQ - Reordenação Drag & Drop (Perguntas Frequentes)\r\n\r\n## ❓ Perguntas sobre Funcionalidade\r\n\r\n### P: Como ativo a reordenação no meu componente?\r\n**R**: Adicione a prop `sortable=\"true\"` ao DynamicList:\r\n```vue\r\n<DynamicList\r\n  :schema=\"schema\"\r\n  :data=\"data\"\r\n  :sortable=\"true\"\r\n  @reorder=\"handleReorder\"\r\n/>\r\n```\r\n\r\n### P: Qual é a diferença entre DynamicList e PropertyListEditor?\r\n**R**: \r\n- **DynamicList.vue**: Componente genérico para exibir coleções de dados com reordenação opcional\r\n- **PropertyListEditor.vue**: Componente especializado para editar propriedades de objetos (metadados) com suporte completo a inline-editing\r\n\r\n### P: O que é o \"drag-handle\"?\r\n**R**: É o ícone `⋮⋮` (seis pontos) que aparece no início de cada linha quando `sortable=\"true\"`. Você deve clicar/arrastar nele para mover a linha de posição.\r\n\r\n### P: Preciso atualizar a API quando reordenar?\r\n**R**: Não imediatamente. O componente emite o evento `reorder` com a nova ordem. Você deve:\r\n1. Capturar o evento\r\n2. Marcar como \"dirty\" (isDirty = true)\r\n3. Aguardar o usuário clicar \"Salvar\"\r\n4. Então enviar para a API\r\n\r\n### P: Como funciona a sincronização com o estado \"dirty\"?\r\n**R**: \r\n```typescript\r\n@reorder=\"(newList) => {\r\n  isDirty = true;  // Marca como modificado\r\n  dataList = newList;  // Atualiza dados locais\r\n  toast.add({ severity: 'info', summary: 'Alteração pendente' });\r\n}\"\r\n```\r\n\r\n### P: Posso reordenar dentro de um grupo específico?\r\n**R**: Sim. Use a propriedade `group` no componente:\r\n```javascript\r\nconst dragOptions = {\r\n  group: \"meu-grupo\",  // Restringe a qual grupo pode arrastar\r\n  // ...\r\n}\r\n```\r\n\r\n### P: O que acontece se o usuário sair sem salvar?\r\n**R**: Dois comportamentos:\r\n1. **PropertyListEditor**: Detecta isDirty e avisa (\"Existem alterações não salvas\")\r\n2. **DynamicList**: Sem gestão de dirty, você controla no componente pai\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre UI/UX\r\n\r\n### P: Como faço o handle aparecer apenas ao passar o mouse?\r\n**R**: Atualmente ele aparece sempre. Se quiser mudar, adicione CSS:\r\n```css\r\n.drag-handle {\r\n  opacity: 0.3;  /* Invisível */\r\n}\r\n.record-card:hover .drag-handle {\r\n  opacity: 1;  /* Visível ao passar mouse */\r\n}\r\n```\r\n\r\n### P: Posso customizar o ícone do handle?\r\n**R**: Sim! Edite em DynamicList.vue ou PropertyListEditor.vue:\r\n```vue\r\n<!-- Antes -->\r\n<i class=\"pi pi-bars text-gray-400 text-sm\"></i>\r\n\r\n<!-- Depois (exemplo com ícone de drag) -->\r\n<i class=\"pi pi-arrow-down-up text-gray-400 text-sm\"></i>\r\n```\r\n\r\n### P: Qual é a cor durante o arraste?\r\n**R**: Configurada em CSS no `.drag` class:\r\n```css\r\n.drag {\r\n  opacity: 1;\r\n  transform: rotate(2deg) scale(1.02);\r\n  box-shadow: 0 5px 25px rgba(99, 102, 241, 0.3);  /* Azul índigo */\r\n}\r\n```\r\n\r\n### P: Posso mudar a duração da animação?\r\n**R**: Sim, no `dragOptions`:\r\n```javascript\r\nconst dragOptions = {\r\n  animation: 200,  // ms (mude aqui)\r\n  // ...\r\n}\r\n```\r\n\r\n### P: Como funciona no mobile?\r\n**R**: Funciona normalmente, mas considere:\r\n- Handle talvez seja pequeno (aumentar em mobile)\r\n- Arraste de toque é suportado\r\n- Recomenda-se aumentar padding em telas pequenas\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Dados\r\n\r\n### P: Os dados são salvos automaticamente ao reordenar?\r\n**R**: Não. Você deve:\r\n1. Capturar evento `reorder`\r\n2. Atualizar estado local\r\n3. **Manualmente** chamar API ao clicar \"Salvar\"\r\n\r\nExemplo:\r\n```typescript\r\nfunction handleReorder(newOrder) {\r\n  localData.value = newOrder;  // Local\r\n  isDirty.value = true;        // Marcar como pendente\r\n  // Não salva ainda!\r\n}\r\n```\r\n\r\n### P: Como garanto que a ordem é única?\r\n**R**: A ordem é determinada pelo índice no array. Vue mantém a reatividade automaticamente.\r\n\r\n### P: E se duas propriedades tiverem o mesmo nome?\r\n**R**: Isso causaria conflito. Implemente validação:\r\n```typescript\r\nfunction validatePropertyName(newName) {\r\n  const exists = editingObject.properties.some(p => p.name === newName);\r\n  if (exists) {\r\n    toast.add({ severity: 'error', summary: 'Nome já existe' });\r\n    return false;\r\n  }\r\n  return true;\r\n}\r\n```\r\n\r\n### P: Como desfaço uma reordenação?\r\n**R**: Três opções:\r\n1. **Sem salvar**: Recarregue a página (dados não salvos são perdidos)\r\n2. **Com salvar**: Reordene novamente manualmente\r\n3. **Undo avançado**: Implemente stack de mudanças (ver roadmap)\r\n\r\n### P: Posso reordenar entre múltiplas listas?\r\n**R**: Apenas se as listas tiverem o mesmo `group`:\r\n```typescript\r\n// Lista A\r\nconst dragOptionsA = { group: \"shared\" };\r\n\r\n// Lista B  \r\nconst dragOptionsB = { group: \"shared\" };\r\n\r\n// Agora itens podem ir de A para B e vice-versa\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Performance\r\n\r\n### P: Qual é o limite de propriedades que posso reordenar?\r\n**R**: Teoricamente ilimitado, mas:\r\n- **< 50**: Muito rápido\r\n- **50-200**: Rápido\r\n- **200+**: Considere virtualização (ainda não implementada)\r\n\r\n### P: Há lag ao arrastar muitos itens?\r\n**R**: Se houver, verifique:\r\n1. Número de computed properties\r\n2. Watchers profundos\r\n3. Tamanho dos dados renderizados\r\n4. Performance do navegador (DevTools > Performance)\r\n\r\n### P: Como otimizo a renderização?\r\n**R**: \r\n```typescript\r\n// ✅ BOM: Computed para dados filtrados\r\nconst visibleProperties = computed(() => {\r\n  return properties.value.filter(p => p.show_in_list);\r\n});\r\n\r\n// ❌ EVITE: Lógica no template\r\n<div v-for=\"p in properties.filter(p => p.show_in_list)\">\r\n```\r\n\r\n### P: Devo usar `v-key=\"item.id\"` ou `v-key=\"index\"`?\r\n**R**: Sempre `item.id` se disponível. O índice muda ao reordenar, causando re-renders desnecessários.\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Integração\r\n\r\n### P: Como integro com dados do backend?\r\n**R**: \r\n```typescript\r\n// 1. Fetch dos dados\r\nconst properties = ref([]);\r\nonMounted(async () => {\r\n  properties.value = await $fetch('/api/object/lead/properties');\r\n});\r\n\r\n// 2. Componente com sortable\r\n<PropertyListEditor\r\n  :properties=\"properties\"\r\n  @reorder=\"onReorder\"\r\n/>\r\n\r\n// 3. Handler\r\nfunction onReorder(newOrder) {\r\n  isDirty = true;\r\n  // Salvar mais tarde com API call\r\n}\r\n```\r\n\r\n### P: Como funciona com Pinia store?\r\n**R**: \r\n```typescript\r\n// store/object.ts\r\nconst properties = ref([]);\r\n\r\nfunction setProperties(newProperties) {\r\n  properties.value = newProperties;\r\n}\r\n\r\nfunction reorderProperties(newOrder) {\r\n  properties.value = newOrder;\r\n  isDirty = true;  // Marcar store como dirty\r\n  // Salvar quando necessário\r\n}\r\n```\r\n\r\n### P: Como sincronizo com Sistema de Manifesto?\r\n**R**: O Schema Manager já faz isso. Seu objeto é:\r\n```typescript\r\neditingObject.value.properties = reorderedProperties;  // Atualiza referência\r\nisDirty.value = true;  // Marca para salvar\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Debugging\r\n\r\n### P: Como vejo quais eventos estão sendo disparados?\r\n**R**: Adicione logs no handler:\r\n```typescript\r\nfunction onReorder(newOrder) {\r\n  console.log('[REORDER EVENT]', newOrder);\r\n  console.log('[ORDER NAMES]', newOrder.map(p => p.name));\r\n}\r\n```\r\n\r\n### P: Como verifico o estado drag durante animação?\r\n**R**: Use DevTools:\r\n1. Abra Elements/Inspector\r\n2. Selecione um item durante arraste\r\n3. Veja classe `.drag` sendo aplicada\r\n\r\n### P: Como verifico se isDirty está sendo marcado?\r\n**R**: \r\n```typescript\r\nwatch(() => isDirty.value, (newVal) => {\r\n  console.log('[DIRTY CHANGED]', newVal);\r\n});\r\n```\r\n\r\n### P: Por que o evento reorder é emitido múltiplas vezes?\r\n**R**: Verifique se você tem múltiplos watchers:\r\n```typescript\r\n// ❌ PROBLEMA: Watcher duplicado\r\nwatch(properties, () => {\r\n  emit('reorder', properties.value);  // Emite sempre que muda\r\n});\r\n\r\n// ✅ SOLUÇÃO: Emita apenas no @end do draggable\r\n@end=\"onDragEnd\"\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Erros Comuns\r\n\r\n### P: \"Cannot read property 'name' of undefined\"\r\n**R**: Propriedade está null. Verifique:\r\n```typescript\r\n// ✅ BOM: Validação\r\nconst propName = property?.name || 'Unknown';\r\n\r\n// ❌ EVITE: Sem checar\r\nconst propName = property.name;  // Erro se property = null\r\n```\r\n\r\n### P: Array não atualiza após reordenar\r\n**R**: Você está mutando diretamente? Use Vue.set:\r\n```typescript\r\n// ❌ ERRADO\r\nproperties[0] = newValue;  // Vue não detecta\r\n\r\n// ✅ CORRETO\r\nproperties.value[0] = newValue;  // Reativo\r\n// ou\r\nproperties.value = [...properties.value];  // Novo array\r\n```\r\n\r\n### P: Drag & Drop não funciona\r\n**R**: Verifique:\r\n1. `vuedraggable` está importado?\r\n2. Prop `sortable=\"true\"` foi adicionado?\r\n3. Handle `.drag-handle` existe no template?\r\n4. Browser suporta drag & drop?\r\n\r\n### P: Estilos não aplicam durante arraste\r\n**R**: Você está importando o CSS de `.drag`?\r\n```vue\r\n<style scoped>\r\n.drag {\r\n  opacity: 1;\r\n  box-shadow: 0 5px 25px rgba(99, 102, 241, 0.3);\r\n}\r\n</style>\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Acessibilidade\r\n\r\n### P: Como faço reordenação acessível via teclado?\r\n**R**: Isso ainda não foi implementado. Você pode:\r\n1. Adicionar botões \"Mover Para Cima\"/\"Mover Para Baixo\"\r\n2. Usar Shift + Setas para reordenar (custom)\r\n3. Implementar ARIA labels\r\n\r\nExemplo de botões:\r\n```vue\r\n<Button \r\n  icon=\"pi pi-arrow-up\"\r\n  @click=\"moveUp(idx)\"\r\n  aria-label=\"Mover para cima\"\r\n/>\r\n<Button \r\n  icon=\"pi pi-arrow-down\"\r\n  @click=\"moveDown(idx)\"\r\n  aria-label=\"Mover para baixo\"\r\n/>\r\n```\r\n\r\n### P: Qual é o aria-label do handle?\r\n**R**: Não tem atualmente. Adicione se necessário:\r\n```vue\r\n<div class=\"drag-handle\" aria-label=\"Arrastar para reordenar\">\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Roadmap\r\n\r\n### P: Vocês vão implementar Undo/Redo?\r\n**R**: Não está planned ainda, mas é possível usando:\r\n```typescript\r\nconst history = ref([]);\r\nconst historyIndex = ref(-1);\r\n\r\nfunction saveToHistory() {\r\n  history.value = history.value.slice(0, historyIndex.value + 1);\r\n  history.value.push(JSON.parse(JSON.stringify(properties.value)));\r\n  historyIndex.value++;\r\n}\r\n\r\nfunction undo() {\r\n  if (historyIndex.value > 0) {\r\n    historyIndex.value--;\r\n    properties.value = JSON.parse(JSON.stringify(history.value[historyIndex.value]));\r\n  }\r\n}\r\n```\r\n\r\n### P: Quando virá array virtual para 1000+ itens?\r\n**R**: Não está planneed. Use paginação ou virtualScroller de PrimeVue.\r\n\r\n### P: Vocês vão adicionar persistência automática?\r\n**R**: Considere debounce + auto-save:\r\n```typescript\r\nconst saveToDebounce = useDebounceFn(saveChanges, 2000);\r\n\r\nfunction onReorder(newOrder) {\r\n  isDirty.value = true;\r\n  saveToDebounce();  // Salva automaticamente após 2s\r\n}\r\n```\r\n\r\n---\r\n\r\n## ❓ Perguntas sobre Suporte\r\n\r\n### P: Funciona em Safari?\r\n**R**: Sim, com vuedraggable 4.0+. Tested em Safari 15+.\r\n\r\n### P: Funciona em IE11?\r\n**R**: Não. Suporte apenas para navegadores modernos (Chrome, Firefox, Safari, Edge).\r\n\r\n### P: Posso usar com jQuery?\r\n**R**: Não, este é um projeto Vue 3. jQuery não é suportado.\r\n\r\n### P: Qual é o licença deste código?\r\n**R**: Mesmo projeto (verificar LICENSE.md).\r\n\r\n---\r\n\r\n## 📞 Contato & Suporte\r\n\r\nSe você não encontrou resposta aqui:\r\n1. Verifique [IMPLEMENTATION_DRAG_DROP.md](IMPLEMENTATION_DRAG_DROP.md)\r\n2. Verifique [TESTING_GUIDE.md](TESTING_GUIDE.md)\r\n3. Procure nos comentários do código\r\n4. Abra uma issue no GitHub\r\n\r\n---\r\n\r\n**Última Atualização**: 17/02/2026\r\n"}