Javascript: формирование csv файла

Задача: на чистом javascript сформировать и сохранить из браузера файл формата csv, адекватно открывающийся табличным редактором (например OnlyOffice)

Решение:

rows=[];
rows.push(["aa","bb"]);

let csvContent = "data:text/csv;charset=utf-8," + rows.map(e => e.join(",")).join("\n");
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "download.csv");
document.body.appendChild(link); 
link.click();

Что тут происходит: заполняется некий массив, далее создаётся ссылка в DOM, и в элемент ссылки записываются данные массива. Далее эмулируется нажатие собственно на эту ссылку.

API Map Yandex: Изменение содержимого метки «на лету»

Задача: разместить внутри метки поле ввода текста (комментарий) и сохранять его значение

Решение:

При формировании Json данных FeatureCollection, внутри каждой метки, в настройке balloonContentBody разместим теги <textarea style=’width: 100%;’></textarea>. И кнопку сохранения результата. Но! Сохранить результат в БД не сложно. Сложно добиться того, чтобы то что пользователь ввел в поле, сохранилось, после перевыбора метки мышкой. Содержимое поля скидывается каждый раз к изначальному, т.к. движек яндекса каждый раз перерисовывает отображение html на основании данных которые у него » в душе». Поэтому функция сохранения будет выглядеть как-то так:

function SaveComment(ls_id){
    console.log("-сохраняем комментарий "+ls_id);
    comment=$("#comment_"+ls_id).val();
    $.post("?r=receipts2/savecomment", {  
            ls_id:ls_id,
            comment:comment
    }).done(function(data) {                        
        console.log(data);
        balloonContentBody=objectManager.objects.getById(ls_id).properties.balloonContentBody;
        start_=balloonContentBody.slice(0,balloonContentBody.search("%;'")+4);
        end_=balloonContentBody.slice(balloonContentBody.search("</textarea>"),balloonContentBody.length);
        balloonContentBody=start_+comment+end_;
        objectManager.objects.setObjectProperties(ls_id,{balloonContentBody:balloonContentBody});
    });                      
}

Что тут происходит?

  1. Изменения сохраняются в базу данных при помощи вызова скрипта receipts2/savecomment
  2. Читаем данные которые яндекс хранит у себя в нутри
  3. Изменем эти данные, добавив комментарий
  4. Сохраняем данные «внутри»

В результате после перещелкивания по метке, комментарий сохраняется.

JavaScript: улучшаем понимание работы функций

Классически функция объявляется используется примерно так:

function Inc(s,n){
  return s+n;
};

Однако её можно объявить и так:

const Inc=(s,n)=>{
  return s+n; 
}

Кроме того! Можно еще короче, используя не явный return:

const Inc=(s,n)=>s+n;

Такие сокращения мне не очень нравятся (дело привычки больше), но тем не менее их удобно применять в некоторых случаях. Например если необходимо вернуть объект, как результат функции выйдет даже несколько понятнее:

const People=(name,soname,age,comment)=>({
  name:name,
  soname:soname,
  age:age,
  comment:comment
});

aa=People("Вася","Сидоров",18,"Вася обычный школьник")

Или например добавить событие onClick к кнопке на странице при помощи стрелочных функций:

but=document.getElementById('#button1');
but.onclick=()=>{
  console.log("Вася нажал кнопку");
}

Выглядит гораздо проще, чем если бы мы использовали «классическую» запись:

function VasyaPress(){
   console.log("Вася нажал кнопку");
};
but=document.getElementById('#button1');
but.onclick=VasyaPress();

Но! только если код внутри функции не сильно длинный. Иначе всё превращается в кашу.

Javascript: удаление элемента массива

В JavaScript как мне кажется не очень удобная реализация работы с массива. Наверное слишком низкоуровневая по сравнению с другими интерпретируемыми языками программирования. Возможно это даёт большую гибкость, но лично мне не удобно, что для простое удаление элемента массива по виду:

mass=[1,2,3,4];
delete mass[2];

Приводит на самом деле не к удалению элемента массива, а пометке, что элемент пустой. Многие пользуются командой splice:

mass=[1,2,3,4];
mass.splice(2,1)

Или даже filter:

brisks_mass=[1,2,3,4];
brisks_mass=brisks_mass.filter((number)=>number!==3) 

Но как говорится «Мне не зашло» (c), ибо есть с чем сравнивать удобство (Python, PHP и т.д.)

JavaScript: декодирование строки в Base64

Вообще штатно есть функции для кодирования/декодирования: atob / btoa. Но один нюанс: если строчку вида «Hello world!» они кодирую-декодируют легко, то с бинарными файлами выйдет ой. Не, они конечно тоже что-то сделают, но с «тихой ошибкой» — т.е. результат будет, но не верен. Попался так, когда с сервера передавал файл в base64 на клиент javascript, декодировал его примерно так:

let a = document.createElement("a");
let file = new Blob([atob(data.result)], {type: 'application/xlsx'});
a.href = URL.createObjectURL(file);
a.download = "template_0.xlsx";
a.click();

А в результате, с виду вроде бы валидный файл, экселем открываться отказался. А всё потому, что atob не работает со строками в Uicode. Потому обычно используют следующие обертки для кодирования-декодирования:

function base64ToBytes(base64) {
  const binString = atob(base64);
  return Uint8Array.from(binString, (m) => m.codePointAt(0));
}
function bytesToBase64(bytes) {
  const binString = String.fromCodePoint(...bytes);
  return btoa(binString);
}
1 2 3 11