Autor Tema: Usar una función para diferentes variables en JavaScript

0 Usuarios y 1 Visitante están viendo este tema.

02 Abril, 2024, 11:44 pm
Leído 909 veces

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola!

Tengo el siguiente fragmento de JavaScript:

Código: [Seleccionar]
  const cName = e.namedValues['Client Name'][0];
  const cEmail = e.namedValues['Client Email'][0];
  const cAddress = e.namedValues['Client Address'][0];
  const cMobile = e.namedValues['Client Mobile'][0];
  const sendCopy = e.namedValues['Send client a copy?'][0];
  const paymentType = e.namedValues['What is your agreed upon payment schedule?'][0];
  const fixedCost = e.namedValues['What was your agreed upon cost for the project?'][0];
  const hourlyRate = e.namedValues['Hourly Rate'][0];
  const manHours = e.namedValues['Total man hours'][0];
  const services = e.namedValues['Select the services'][0];

Necesito que la entrada del usuario a través de los campos en un Google Form no contengan más de un espacio, para eso diseñé la siguiente función:

Código: [Seleccionar]
function quitarExtras(data) {
  return typeof(data) === "string" ? data.split(' ').filter(Boolean).join(' ') : data;
}

Ahora lo que debería hacer sería usar esta función en cada línea de código:

Código: [Seleccionar]
  const cName = quitarExtras(e.namedValues['Client Name'][0]);
  const cEmail = quitarExtras(e.namedValues['Client Email'][0]);
  const cAddress = quitarExtras(e.namedValues['Client Address'][0]);
  const cMobile = quitarExtras(e.namedValues['Client Mobile'][0]);
  // etcetera

Sin embargo, como observan, es un trabajo muy tedioso de hacer.

¿Hay alguna manera de evitar esta repetición? Pensé en algo como para cada variable del archivo, agregar quitarExtras(...) pero no se me ocurre cómo, ni usar un ciclo for. Tampoco me interesa usar Add-ons.

Gracias!!
Saludos

03 Abril, 2024, 12:29 am
Respuesta #1

Eren

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 134
  • País: mx
  • Karma: +1/-0
  • Sexo: Masculino
El código siguiente itera sobre las propiedades de e.namedValues y aplica una función lambda a sus valores que los filtra con la función que has definido y que los inserta en el objeto filtered bajo el mismo nombre de propiedad que tenían en e.namedValues.
Código: [Seleccionar]
const filtered = {};
Object.keys(e.namedValues).forEach(name => {
    filtered[name] = quitarExtras(e.namedValues[name][0]);
});

Después de aplicar ese código, deberías poder acceder a cada valor filtrado como en el ejemplo siguiente:
Código: [Seleccionar]
const cName = filtered['Client Name'];

03 Abril, 2024, 12:50 am
Respuesta #2

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola

El código siguiente itera sobre las propiedades de e.namedValues y aplica una función lambda a sus valores que los filtra con la función que has definido y que los inserta en el objeto filtered bajo el mismo nombre de propiedad que tenían en e.namedValues.
Código: [Seleccionar]
const filtered = {};
Object.keys(e.namedValues).forEach(name => {
    filtered[name] = quitarExtras(e.namedValues[name][0]);
});

Después de aplicar ese código, deberías poder acceder a cada valor filtrado como en el ejemplo siguiente:
Código: [Seleccionar]
const cName = filtered['Client Name'];

Muchas gracias!! No pensé que alguien del foro iba a poder ayudarme :aplauso: :aplauso:

En un rato lo pruebo, pero así a vuelapluma, ¿no sería rizar el rizo? Tengo que ir línea por línea y modificar e.namedValues[<algo>][0]; por filtered[<algo>]; y quería dejar las declaraciones de constantes sin cambiar por ser algo muy tedioso (por eso quería evitar hacer quitarExtras(e.namedValues[<algo>][0]); en cada lugar).

O no sé si conoces algún método de Find & Replace que haga justamente lo que queremos.

Saludos

03 Abril, 2024, 01:20 am
Respuesta #3

Eren

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 134
  • País: mx
  • Karma: +1/-0
  • Sexo: Masculino
Lo que puedes hacer es, en lugar de guardar los valores filtrados en un segundo objeto, sobreescribir las propiedades del objeto original, así:
Código: [Seleccionar]
Object.keys(e.namedValues).forEach(name => {
    e.namedValues[name][0] = quitarExtras(e.namedValues[name][0]);
});

De esa manera, no tienes que reemplazar el código que ya tienes.

03 Abril, 2024, 01:25 am
Respuesta #4

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola

Lo que puedes hacer es, en lugar de guardar los valores filtrados en un segundo objeto, sobreescribir las propiedades del objeto original, así:
Código: [Seleccionar]
Object.keys(e.namedValues).forEach(name => {
    e.namedValues[name][0] = quitarExtras(e.namedValues[name][0]);
});

De esa manera, no tienes que reemplazar el código que ya tienes.

Eso se ve mejor!

Te pongo el código completo de ejemplo obtenido de: https://medium.com/swlh/hacking-it-generate-pdfs-from-google-forms-3ca4fcc5a0aa:

Código: [Seleccionar]
function onSubmit(e) {
  const rg = e.range;
  const sh = rg.getSheet();

  //Get all the form submitted data
  //Note: This data is dependent on the headers. If headers, are changed update these as well.
  const cName = e.namedValues['Client Name'][0];
  const cEmail = e.namedValues['Client Email'][0];
  const cAddress = e.namedValues['Client Address'][0];
  const cMobile = e.namedValues['Client Mobile'][0];
  const sendCopy = e.namedValues['Send client a copy?'][0];
  const paymentType = e.namedValues['What is your agreed upon payment schedule?'][0];
  const fixedCost = e.namedValues['What was your agreed upon cost for the project?'][0];
  const hourlyRate = e.namedValues['Hourly Rate'][0];
  const manHours = e.namedValues['Total man hours'][0];
  const services = e.namedValues['Select the services'][0];

  //Consequential Data
  const tax = 18.5
  var subtotal = 0;
  var taxAmt = 0;
  var payableAmt = 0;

  //if the user has selected hourly payment model
  //Note: Be careful that the responses match the elements on the actual form
  switch (paymentType) {
    case 'Hourly Rate':
      subtotal = hourlyRate * manHours;
      taxAmt = subtotal * (tax / 100);
      payableAmt = +subtotal + +taxAmt;
      break;
    case 'Fixed Cost':
      subtotal = fixedCost;
      taxAmt = fixedCost * (tax / 100)
      payableAmt = +fixedCost + +taxAmt;
      break;
  }

  const invoiceID = 'IN' + Math.random().toString().substr(2, 9);
  var formattedDate = Utilities.formatDate(new Date(), "IST", "dd-MMM-yyyy");

  //Set the consequential data in the columns of the spreadsheet for record keeping
  //Note: These variable are dependent on the sheet's columns so if that changes, please update.
  const row = rg.getRow();

  const payableAmtCol = 2; //B
  const invoiceIDCol = 3; //C

  sh.getRange(row, payableAmtCol).setValue(payableAmt);
  sh.getRange(row, invoiceIDCol).setValue(invoiceID);


  //Build a new invoice from the file
  //Folder and file IDs
  const invoiceFolderID = '<invoice-folder-id>';
  const invoiceFolder = DriveApp.getFolderById(invoiceFolderID);

  const templateFileID = '<template-id>';
  const newFilename = 'Invoice_' + invoiceID;

  //Make a copy of the template file
  const newInvoiceFileID = DriveApp.getFileById(templateFileID).makeCopy(newFilename, invoiceFolder).getId();;

  //Get the invoice body into a variable
  var document = DocumentApp.openById(newInvoiceFileID);
  var body = document.getBody();

  //Replace all the {{ }} text in the invoice body
  body.replaceText('{{Invoice num}}', invoiceID);
  body.replaceText('{{Date}}', formattedDate);
  body.replaceText('{{Client Name}}', cName);
  body.replaceText('{{Client Address}}', cAddress);
  body.replaceText('{{Client Mobile}}', cMobile);
  body.replaceText('{{Client Email}}', cEmail);
  body.replaceText('{{Services}}', services.split(', ').join('\n'));

  body.replaceText('{{Subtotal}}', subtotal);
  body.replaceText('{{Tax Value}}', taxAmt);
  body.replaceText('{{Total}}', payableAmt);

  //In the case of hourly rate payment type, let's add an additional message giving the rate and the man hours.
  if (paymentType.includes('Hourly Rate')) {
    //It should look something like this on the invoice
    //Hourly Rate
    //Rate of Rs.1200/hour
    //Completed 50 man hours
    const message = paymentType + '\nRate of Rs.' + hourlyRate + '/hour\nCompleted ' + manHours + ' man hours';
    body.replaceText('{{Payment Type}}', message);
  } else {
    body.replaceText('{{Payment Type}}', paymentType);
  }

  document.saveAndClose();

  //If you have selected to directly send it via email
  if (sendCopy.includes('Yes')) {
    //send email with the file
    var attachment = DriveApp.getFileById(newInvoiceFileID);
    GmailApp.sendEmail(cEmail, '<subject>,
                     '<body>',
      {
        attachments: [attachment.getAs(MimeType.PDF)],
        from: '<your-email>@gmail.com'
      });
  }
}

(Es código js pero es de Google Apps Scripts)

¿Dónde debería poner eso? ¿Antes de declarar las constantes (o sea, debajo de la línea const sh = rg.getSheet()) o después de declararlas (antes de //Consequential Data)?

Si es posible, no quisiera usar la función replaceText, porque no sé bien cómo funciona.

Muchas gracias nuevamente.

Saludos

03 Abril, 2024, 01:30 am
Respuesta #5

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola

Me autorespondo: Al principio de todo.

Muchas gracias! Por lo que veo funciona a la perfección. Si surge algún otro problema, avisaré. ;D

Saludos

03 Abril, 2024, 01:34 am
Respuesta #6

Eren

  • $$\Large \color{#5e8d56}\pi\,\pi\,\pi$$
  • Mensajes: 134
  • País: mx
  • Karma: +1/-0
  • Sexo: Masculino
Ah, sí, al principio de todo sería correcto. Lo importante es que sea antes de las constantes, pues de otro modo éstas harían referencia a valores no filtrados.

Saludos.