Handler para un formulario de envío de screencast -- javascript campo con jquery campo con form camp codereview Relacionados El problema

Handler for a screencast submission form


4
vote

problema

Español

Tengo un guión monolítico que alimenta este formulario:

captura de pantalla de la forma

Aquí está:

  $(function() {    // Functions   function attainDistinctTags(value) {     var tags = value.split(',');     tags = tags.filter(function(tag) { return /S/.test(tag) });     tags = tags.filter(function(item, pos, self) { return self.indexOf(item) == pos; });     return tags;   }   function parseVideoId(url) {     var pattern = /^.*(youtu.be/|v/|u/w/|embed/|watch?v=|&v=)([^#&?]*).*/;     var match = url.match(pattern);     if (match && match[2].length == 11) {       return match[2];     }   }   function buildVideoApiUrl(id) {     var base = "https://www.googleapis.com/youtube/v3/videos";     var parts = "snippet,contentDetails";     var key = "AIzaSyCKQFYlDRi5BTd1A-9rhFjF8Jb_Hlfnquk";     return base + "?part=" + parts + "&id=" + id + "&key=" + key;   }    // Validation   $.validator.addMethod("youtubeVideoUrl", function (value, element) {     return /^(https?://)?(www.)?(youtube.com|youtu.?be)/.+$/.test(value);   }, "Please enter a valid YouTube video url.");   $.validator.addMethod("maximumOf2Tags", function (value, element) {     var tags = attainDistinctTags(value);     return tags.length <= 2;   }, "You cannot enter more than two tags.");   $("#submitForm").validate({     ignore: [],     errorElement: "span",     errorClass: "help-block",     highlight: function(element) {       $(element)         .closest('.form-group')         .addClass('has-error')         .removeClass('has-success');     },     unhighlight: function(element) {       $(element)         .closest('.form-group')         .addClass('has-success')         .removeClass('has-error');     },     rules: {       url: {         required: true,         youtubeVideoUrl: true,         remote: function () {           return {             url: buildVideoApiUrl(parseVideoId($("#url").val())),             dataFilter: function(response) {               var json = JSON.parse(response);               return json.items.length !== 0;             }           };         }       },       tags: {         required: true,         maximumOf2Tags: true       }     },     messages: {       url: {         required: "Please enter a screencast link.",         remote: "This video does not exist."       },       tags: {         required: 'Please enter at least one tag.'       }     }   });    // Automatic title and description loading   $("#url").change(function() {     var videoUrl = $(this).val();     // if the input is not a valid YouTube url, return.     if(!$(this)[0].checkValidity()) {       return;     }     var id = parseVideoId(videoUrl);     var apiUrl = buildVideoApiUrl(id);     $.get(apiUrl, function(data) {       var item = data.items[0];       // if the video does not exist       if (item == undefined) {         $("#title").val('');         $("#description").val('');         $("#channelName").val('');       } else {         $("#title").val(item.snippet.title);         $("#description").val(item.snippet.description);         $("#channelName").val(item.snippet.channelTitle);       }     });   });    // Tag input control   $("#tags-input").keyup(function() {     var tags = attainDistinctTags($(this).val());     $("#tag-list").empty();     tags.forEach(function(tag) {       $("#tag-list").append("<li> <span class="fa fa-tag"></span>" + tag + "</li>");     });   });    // Tag autocomplete   function split(val) {     return val.split(/,s*/);   }   function extractLast(term) {     return split(term).pop();   }   $('#tags-input').bind('keydown', function(event) {     if ( event.keyCode === $.ui.keyCode.TAB &&       $( this ).autocomplete( "instance" ).menu.active ) {         event.preventDefault();       }   }).autocomplete({     source: function( request, response ) {       $.getJSON( "/api/tags", {         term: extractLast( request.term )       }, response );     },     focus: function() {       return false;     },     select: function( event, ui ) {       var terms = split( this.value );       terms.pop();       terms.push( ui.item.value );       terms.push( "" );       this.value = terms.join( ", " );       return false;     }   });  });   

Tiene 4 responsabilidades distintas:

  1. Validación
  2. autocompletar
  3. Poblando automáticamente el disabled Campos Cuando el usuario ingresa a un enlace de YouTube
  4. que representa una lista de etiquetas

En este momento, uso comentarios para hacer que el código sea un poco más fácil de leer, pero nunca haría esto en el servidor: el código monolítico es malo.

¿Cómo puede descomponer este código en partes más pequeñas?

Original en ingles

I have a monolithic script that powers this form:

Screenshot of form

Here it is:

$(function() {    // Functions   function attainDistinctTags(value) {     var tags = value.split(',');     tags = tags.filter(function(tag) { return /\S/.test(tag) });     tags = tags.filter(function(item, pos, self) { return self.indexOf(item) == pos; });     return tags;   }   function parseVideoId(url) {     var pattern = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;     var match = url.match(pattern);     if (match && match[2].length == 11) {       return match[2];     }   }   function buildVideoApiUrl(id) {     var base = "https://www.googleapis.com/youtube/v3/videos";     var parts = "snippet,contentDetails";     var key = "AIzaSyCKQFYlDRi5BTd1A-9rhFjF8Jb_Hlfnquk";     return base + "?part=" + parts + "&id=" + id + "&key=" + key;   }    // Validation   $.validator.addMethod("youtubeVideoUrl", function (value, element) {     return /^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/.test(value);   }, "Please enter a valid YouTube video url.");   $.validator.addMethod("maximumOf2Tags", function (value, element) {     var tags = attainDistinctTags(value);     return tags.length <= 2;   }, "You cannot enter more than two tags.");   $("#submitForm").validate({     ignore: [],     errorElement: "span",     errorClass: "help-block",     highlight: function(element) {       $(element)         .closest('.form-group')         .addClass('has-error')         .removeClass('has-success');     },     unhighlight: function(element) {       $(element)         .closest('.form-group')         .addClass('has-success')         .removeClass('has-error');     },     rules: {       url: {         required: true,         youtubeVideoUrl: true,         remote: function () {           return {             url: buildVideoApiUrl(parseVideoId($("#url").val())),             dataFilter: function(response) {               var json = JSON.parse(response);               return json.items.length !== 0;             }           };         }       },       tags: {         required: true,         maximumOf2Tags: true       }     },     messages: {       url: {         required: "Please enter a screencast link.",         remote: "This video does not exist."       },       tags: {         required: 'Please enter at least one tag.'       }     }   });    // Automatic title and description loading   $("#url").change(function() {     var videoUrl = $(this).val();     // if the input is not a valid YouTube url, return.     if(!$(this)[0].checkValidity()) {       return;     }     var id = parseVideoId(videoUrl);     var apiUrl = buildVideoApiUrl(id);     $.get(apiUrl, function(data) {       var item = data.items[0];       // if the video does not exist       if (item == undefined) {         $("#title").val('');         $("#description").val('');         $("#channelName").val('');       } else {         $("#title").val(item.snippet.title);         $("#description").val(item.snippet.description);         $("#channelName").val(item.snippet.channelTitle);       }     });   });    // Tag input control   $("#tags-input").keyup(function() {     var tags = attainDistinctTags($(this).val());     $("#tag-list").empty();     tags.forEach(function(tag) {       $("#tag-list").append("<li> <span class=\"fa fa-tag\"></span>" + tag + "</li>");     });   });    // Tag autocomplete   function split(val) {     return val.split(/,\s*/);   }   function extractLast(term) {     return split(term).pop();   }   $('#tags-input').bind('keydown', function(event) {     if ( event.keyCode === $.ui.keyCode.TAB &&       $( this ).autocomplete( "instance" ).menu.active ) {         event.preventDefault();       }   }).autocomplete({     source: function( request, response ) {       $.getJSON( "/api/tags", {         term: extractLast( request.term )       }, response );     },     focus: function() {       return false;     },     select: function( event, ui ) {       var terms = split( this.value );       terms.pop();       terms.push( ui.item.value );       terms.push( "" );       this.value = terms.join( ", " );       return false;     }   });  }); 

It has 4 distinct responsibilites:

  1. Validation
  2. Autocomplete
  3. Automatically populating the disabled fields when the user enters a YouTube link
  4. Rendering a tag list

At the moment I use comments to make the code a bit easier to read but I would never do this on the server - monolithic code is bad.

How can break this code down into smaller parts?

        

Lista de respuestas

1
 
vote

Estás dividiendo una cadena separada por comas y obtendrá solo la primera aparición de una cadena. Dos filtros son costosos y una expresión regular creada en cada iteración es también. Lo siguiente podría ser mejor. En su lugar, usaremos el recorte para ver si hay una palabra y, al mismo tiempo, verifique la ocurrencia.

  var series1 = new XYChart.Series(); series1.setName("Reference portfolio");  [new XYChart.Data(1,2),  new XYChart.Data(2,1),  new XYChart.Data(3,9),  new XYChart.Data(4,5),  new XYChart.Data(5,7),  new XYChart.Data(6,6) ].forEach(function(item){     series1.data.add(item); }); 1  

Es posible que desee pasar a los valores de "constantes" que podrían ser configurables. En su caso, puede mudarse el var series1 = new XYChart.Series(); series1.setName("Reference portfolio"); [new XYChart.Data(1,2), new XYChart.Data(2,1), new XYChart.Data(3,9), new XYChart.Data(4,5), new XYChart.Data(5,7), new XYChart.Data(6,6) ].forEach(function(item){ series1.data.add(item); }); 2 en la división, 99887776655443313 var series1 = new XYChart.Series(); series1.setName("Reference portfolio"); [new XYChart.Data(1,2), new XYChart.Data(2,1), new XYChart.Data(3,9), new XYChart.Data(4,5), new XYChart.Data(5,7), new XYChart.Data(6,6) ].forEach(function(item){ series1.data.add(item); }); 4 , la URL base y las diversas expresiones regulares que usted tener. Si desea mantenerlos "funcional", sus llamadas pueden pasarlas en:

  var series1 = new XYChart.Series(); series1.setName("Reference portfolio");  [new XYChart.Data(1,2),  new XYChart.Data(2,1),  new XYChart.Data(3,9),  new XYChart.Data(4,5),  new XYChart.Data(5,7),  new XYChart.Data(6,6) ].forEach(function(item){     series1.data.add(item); }); 5  

Evite modificar el DOM por iteración. Le sugiero que elimine el elemento de la DOM primero, agregue los contenidos, luego adjunte nuevamente a la DOM. La ganancia perfecta puede ser insignificante, por lo que depende de usted. El siguiente código es terrible, pero la idea está ahí.

  var series1 = new XYChart.Series(); series1.setName("Reference portfolio");  [new XYChart.Data(1,2),  new XYChart.Data(2,1),  new XYChart.Data(3,9),  new XYChart.Data(4,5),  new XYChart.Data(5,7),  new XYChart.Data(6,6) ].forEach(function(item){     series1.data.add(item); }); 6  
 

You're splitting a comma separated string and getting only the first occurrence of a string. Two filters are costly and a regular expression created on each iteration is too. The following might be better. Instead, we'll use trim to see if there is a word and at the same time, check the occurrence.

function attainDistinctTags(value) {   return value.split(',').filter(function(tag, position, tags){     return tag.trim().length && tags.indexOf(tag) === pos;   }); } 

You might want to move out to "constants" values that could possibly be configurable. In your case, you can move out the , in the split, the 11 of parseVideoId, the base url, and the various regular expressions you have. If you want to keep them "functional", your callers can pass them in:

var TAG_DELIMITER = ',';  function attainDistinctTags(value, delimiter) {   return (value || []).split(delimiter).filter(function(tag, position, tags){     return tag.trim().length && tags.indexOf(tag) == pos   }); }  attainDistinctTags(tags, TAG_DELIMITER); 

Avoid modifying the DOM per iteration. I suggest you remove the element from the DOM first, append the contents, then append it back to the DOM. Perf gain may be negligible, so its up to you. The following code is terrible, but the idea is there.

$("#tags-input").keyup(function() {   var tags = attainDistinctTags($(this).val());   var tagList = $("#tag-list");   var tagListContainer = tagList.parent();   tagList.detach().empty();   tags.forEach(tag => tagList.append("..."));   tagListContainer.append(tagList); }); 
 
 

Relacionados problema

1  Formulario de validación JavaScript  ( Validation form javascript ) 
Soy un principiante para JavaScript y sé sobre las validaciones de jQuery, sin embargo, no quiero usar una base como jQuery todavía. Me pregunto si lo que h...

6  Validación básica de forma  ( Basic form validation ) 
Pregunta + Resultado deseado El código a continuación funciona actualmente, sin embargo, no estoy convencido de que la utilización de un 9988777666554433...

1  ¿Hay una forma de secadora para crear este generador de cita jQuery?  ( Is there a dryer way to create this jquery quote generator ) 
Esta es una de mis primeras aplicaciones reales que he realizado con JavaScript (jQuery), por lo que sé que mi enfoque probablemente no sea el mejor y mi larg...

1  Pumular las desplegaciones de la provincia de la provincia de la ciudad de la consulta de la Firana  ( Populate country province city dropdowns from firebase query ) 
Soy nuevo en Firebase y soy un desarrollador de SQL en recuperación, por lo que no he envuelto mi mente en todos los aspectos de las consultas de Firsebase. T...

2  Formulario de clases de clase y clases infantiles  ( Form validator class and child classes ) 
Estoy creando una clase de formulario para validar los datos del formulario, y quisiera algunos consejos sobre cómo refactorizarlo por las mejores prácticas. ...

2  Usando jQuery para configurar la clase de un elemento correspondiente al botón de radio seleccionado  ( Using jquery to set the class of an element corresponding to the selected radio ) 
Soy un poco nuevo con jQuery, pero puede hacerlo trabajar para realizar la funcionalidad que estoy buscando. La siguiente función verifica el valor de la en...

3  Verificando que todos los campos de formulario se completan  ( Verifying that all form fields are filled in ) 
Agarré la forma de algún sitio aleatorio porque solo estoy interesado escribir el Javascript en este momento. Estoy tratando de verificar que un usuario hay...

2  Validación instantánea de la longitud del campo de la forma  ( Instantaneous validation of form field length ) 
Dado que tengo una función que se puede hacer de unas maneras como de costumbre, me preguntaba qué sigue es el mejor para lograr la validación del formulario ...

5  Validación del formulario AJAX  ( Ajax form validation ) 
Este es mi primer intento de la validación del formulario AJAX, y todo funciona como se esperaba, el ejemplo final final mantendrá muchos más campos de entrad...

7  Clase Forma Formulario PHP  ( Php form builder class ) 
Me gustaría revisar mi clase de generador de formularios. Quiero saber sobre los siguientes temas: es este eficiente? ¿Esto tiene alguna falla? es esto...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos