Dalam proyek yang saya kerjakan, kami perlu membuat objek JSON yang berisi struktur hierarki organisasi dan data yang terkait dengan setiap organisasi. Saya akan memberikan contoh untuk menjelaskan konsep ini dengan lebih baik.

- org_level_one
-x address
-x email
-x children
-- org_level_two
--x email
--x address
-- org_level_two
--x email
--x address
--x children
--- org_level_three
---x email
...

Semoga Anda mendapatkan idenya. Mungkin terdapat sejumlah organisasi dan sejumlah tingkat hubungan orang tua/anak. Setiap organisasi hanya perlu memiliki satu kumpulan data tentang hal-hal seperti email, alamat, URL, dll. dan setiap organisasi hanya dapat memiliki satu induk. Namun, setiap organisasi dapat memiliki sejumlah anak dan mereka dapat diganti namanya serta dipindahkan ke tingkat hierarki yang lain.

Mengapa Menggunakan File CSV?

Sebuah pertanyaan yang sangat bagus untuk ditanyakan. CSV umumnya tidak digunakan untuk menyimpan informasi yang ada dalam struktur mirip pohon. Saya awalnya diberi file CSV dengan daftar organisasi dan data yang terkait dengan masing-masing organisasi. Hubungan induk/anak adalah empat kolom pertama dan kolom sisanya adalah data. Setelah mencoba beberapa hal, saya berpikir mengapa menggunakan file CSV sebagai pengganti membangun UI di JS yang akan membuat objek JSON yang sesuai dan dikirim ke server untuk penyimpanan dan pengambilan?

Dalam alur kerja tersebut, file CSV dapat digunakan untuk mengisi data yang diperlukan untuk objek JSON terlebih dahulu, lalu UI akan mengambil alih untuk pengeditan di masa mendatang. Dengan skenario ini, berpindah-pindah organisasi dalam hierarki akan menjadi mudah dan dapat dilakukan dengan antarmuka seret dan lepas untuk memindahkan semua organisasi turunan beserta induknya. Saya pikir pendekatan itu akan menjadi UX yang jauh lebih bagus.

Namun, kami masih memiliki file CSV yang sedang diedit karena konsumen data sedang dikembangkan bersama dengan alur kerja pengeditan. Jadi, kita perlu mengembangkan beberapa langkah konversi awal. Jika saya sudah perlu mengembangkan bagian alur kerja tersebut, mengapa tidak mencoba dan membatasi alur kerja pada file CSV untuk pengguna. Lagi pula, jika mereka lebih nyaman menggunakan JSON, mereka akan langsung memberi saya format itu, bukan?

Salah satu kegagalan proyek pengembangan yang sering saya lihat dalam karier saya sebagai pengembang web adalah “rekayasa berlebihan”. Saya tidak bisa mengatakan ini cukup…tetapi ketika Anda membawa pengguna keluar dari zona nyaman mereka tanpa alasan selain Anda ingin membuat aplikasi yang dirancang dengan indah sambil mempelajari beberapa trik baru, Anda mungkin telah mengecewakan manajer dan pengguna Anda. yang akan dipaksa untuk menggunakan apa pun yang Anda kembangkan setelah merilisnya. Terkadang…ahem, sering kali, solusi paling sederhana mungkin berhasil dan PoC mungkin memberi Anda wawasan tentang cara menangani masalah secara berbeda. Apa pun yang akhirnya Anda kembangkan, mungkin memerlukan beberapa iterasi sebelum cukup dipoles untuk menghasilkan solusi akhir.

Jika Anda Membangun JS, Mereka Akan Datang

Alasan lain saya ingin beralih dari CSV ke JSON yang akan digunakan oleh aplikasi klien adalah karena biasanya diperlukan proses pembangunan untuk aplikasi JS apa pun yang Anda kembangkan saat ini. Perintah npm run dev dan npm run build, atau yang serupa, adalah perintah yang biasa saya gunakan saat membaca proyek orang lain. Anda dapat melakukan hot reload, transpile, menggunakan sintaksis mewah, dan menggunakan modul node di browser melalui alur kerja tersebut dan alat terkait.

Namun, Anda menimbulkan kompleksitas yang cukup besar dengan semua hal itu. Saya ingat mempelajari Vue.js sambil membuat aplikasi yang dimulai dari file HTML mandiri. Setiap halaman/rute memuat file HTML yang berbeda. Kemudian, saya beralih ke starter kit Vue Webpack dengan komponen file tunggal, pengujian, dan linting yang semuanya bekerja secara otomatis untuk saya dengan sedikit atau tanpa konfigurasi manual. Pengalaman pengembang lebih baik bagi saya, tetapi pengguna akhir dan pengembang lain sebenarnya menyukai versi awal aplikasi yang lebih jelek (yang masih jelek).

Salah satu alasannya terkait dengan perutean. Awalnya, saya tidak menggunakan vue-router karena setiap rute disertakan dalam file HTML. Hal ini menyebabkan duplikasi kode, yang saya coba mitigasi melalui Impor HTML (Safari tidak menyukai “fitur” itu). Karena setiap halaman berisi variabel global dari instance Vue, Anda dapat mengakses variabel tersebut, atau melakukan hal lain…yang mungkin tidak boleh Anda lakukan.

Namun faktanya tetap jauh lebih mudah untuk menjelaskan kepada pengembang lain di mana kode tersebut berada dan apa fungsinya. Saya tidak perlu mengatakan “baik, ini dimulai hanya dengan tag ‹div id=”app”› kosong yang bersarang di dalam templat dengan file lain yang mendefinisikan instance…dan webpack…ES6 pasti…dll…dst…”. Sial, saya masih belum tahu persis cara kerja starter kit Vue Wepack, saya hanya tahu cara menghubungkan rute ke komponen dan mengambilnya dari sana.

Jika Anda mencoba bekerja secara kolaboratif dalam tim di mana pengembang lain mengetahui beberapa jQuery tetapi tidak ES6 dan lain-lain. Al. dan Anda memperkenalkan alat pengembang dan sintaks bahasa baru di atas kerangka JS baru kepada mereka, jangan kaget jika mereka akan keluar. Mereka bahkan mungkin akan membenci Anda setelahnya… lagipula, Anda bersikap egois saat mencoba belajar sambil bekerja dan meninggalkan mereka di bawah bus jika Anda meninggalkan pekerjaan pada suatu saat dengan mendokumentasikan apa pun.

Karena alasan ini, saya memutuskan untuk memulai dengan apa yang diberikan kepada saya, file data CSV. Saya tahu pengguna akhir lebih nyaman menggunakan file CSV dan mereka tidak bisa memasukkan data ke dalam sesuatu yang saya kembangkan tetapi belum selesai. Saya juga tahu bahwa memiliki alur kerja yang sesederhana mungkin dan semoga mudah dipahami akan membantu pengembang lain untuk mengerjakannya di masa mendatang. Terakhir, saya telah melihat proyek-proyek kehilangan pendanaan di tengah-tengah pengembangan sebelum diterapkan ketika solusi yang lebih cepat mungkin telah diterapkan, digunakan, dan dipelihara jika pendekatan yang lebih sederhana dan berpotensi lebih berantakan digunakan.

Berkas…

File asli yang diberikan kepada saya terdiri dari hierarki organisasi di kolom pertama dan data yang terkait dengan organisasi di kolom lainnya.

Hal pertama yang saya perhatikan adalah setiap baris hanya berisi satu data organisasi tetapi juga hubungan orang tua/anak secara keseluruhan. Awalnya, saya melihat empat tingkatan yang dapat ditampung oleh sebuah organisasi; namun, jumlah level dapat berubah seiring berjalannya waktu. Jika tingkatnya bervariasi dari waktu ke waktu, maka data untuk setiap organisasi akan dimasukkan lebih jauh ke dalam kolom-kolom di spreadsheet.

Anda dapat memisahkan data organisasi dari tempatnya dalam hierarki dengan membuat dua spreadsheet. Anda kemudian memiliki kunci asing untuk mencocokkannya dan dapat membuat orang hanya mengedit data atau hierarki.

Namun bagaimana Anda melihat hierarki lengkap saat bekerja dari spreadsheet itu? Anda harus memiliki UI untuk menyusun data tersebut ke dalam urutan yang benar. Oleh karena itu, memiliki data yang memungkinkan pengguna untuk hanya menyalin dan menempelkan baris yang mereka inginkan saat memindahkan organisasi. Mungkin akan lebih merepotkan untuk menggulir ke data di kolom paling kanan spreadsheet, namun setidaknya sifat visual dari hubungannya tetap terjaga.

Agar struktur awal berfungsi, kita dapat meminta pengguna memasukkan jumlah tingkat hierarki, mungkin dengan label header kolomnya, dan menganggap semua header yang tersisa adalah data untuk organisasi di baris tersebut.

Karena kita memilih untuk menjadikan UUID organisasi sebagai kombinasi nama hierarki, kita perlu memikirkan bagaimana pengguna dapat mengubah hubungan tersebut dan kemudian bagaimana konsumen data akan memperbarui untuk mencerminkan perubahan tersebut.

Beruntung bagi kami, karena data dikumpulkan melalui HTTP melalui Apache, solusi potensial mengarahkan pengguna ke data baru jika mereka telah memuat versi cache dari tampilan organisasi sebelum diperbarui. Kami dapat menyimpan pengalihan dalam file terpisah yang dihasilkan pada proses pembangunan setiap kali data berubah. Kita juga dapat membuat file JSON untuk setiap rute yang diperlukan untuk menampilkan data dan memiliki API file datar tanpa memerlukan database untuk mengumpulkan data yang dikirim kembali ke klien.

Bentuk Sederhana; File HTML Sederhana

Untuk UI, yang akan saya lakukan hanyalah membuat formulir sederhana. Sudah lama sekali saya tidak melakukan ini dalam HTML, sehingga saya tidak tahu harus mengetik apa di IDE saya setelah selesai for hingga <form action=""></form>. Saya terbiasa menggunakan semacam kerangka kerja untuk membuat formulir, mengumpulkan data masukan, menambahkan perlindungan CSRF, dan POST ke titik akhir yang tepat untuk persistensi.

Salah satu bagian menyenangkan tentang mengurangi kompleksitas kode Anda adalah Anda kembali ke konsep dasar pengembangan web yang merupakan pengetahuan penting yang digunakan untuk membangun situs web 20 tahun yang lalu, tetapi banyak pengembang yang lupa atau bahkan tidak pernah mempelajari cara melakukannya. Saya memulai pengembangan web menggunakan Drupal CMS dan Form API-nya serta pengontrol depan dan sistem perutean/menu. Baru bertahun-tahun kemudian saya mempelajari apa itu pengontrol depan dan lebih banyak lagi tentang perutean dan siklus hidup permintaan/respons. Namun, saya masih tidak ingat bagaimana membuat formulir yang tepat hanya dalam HTML…jadi jalan saya masih panjang di departemen konsep dasar web.

Untuk menjaga aplikasi kecil ini sesederhana mungkin, saya ingin menjadikannya file HTML yang berdiri sendiri yang dapat dimuat dan diproses oleh seseorang menjadi file JSON pada formulir "pengiriman". Oleh karena itu, tombol kirim menggunakan onclick=”submitData()” untuk memproses file CSV di latar belakang. Alasan saya mengutip "penyerahan" adalah atribut "tindakan" yang biasanya digunakan untuk mengirim data kembali ke server untuk diproses yang kami berpura-pura agar tetap berada di sisi klien.

Saya tidak akan menambahkan kode HTML formulir karena cukup standar, tetapi saya senang mengetahui bahwa mengunggah file cukup mudah dilakukan dalam masukan formulir dengan mengatur jenis dan ekstensi apa yang disertakan.

<input type="file"
       id="csv_upload"
       class="form-control"
       name="csv_upload"
       accept=".csv">

Menangani Input File

Saya tidak tahu cara bekerja dengan unggahan file di browser sebelum mencoba menyelesaikan tugas ini. Setiap kali saya tidak mengetahui sesuatu tentang web, saya membuka situs web MDN yang bagus, dan untungnya bagi saya, mereka memiliki artikel bagus tentang cara menggunakan jenis input file lengkap dengan contohnya.

const uploadFile = document.querySelector('#csv_upload');
uploadFile.addEventListener('change', () => { currentFiles = uploadFile.files});

Artikel MDN menjelaskan bagaimana Anda dapat menggunakan pendengar acara untuk menyimpan file yang dipilih dalam sebuah variabel dan melakukan apa pun yang Anda inginkan dengannya. Mungkin ada baiknya untuk "membaca File Web API", namun kolom input akan memberi Anda daftar objek file yang nantinya dapat Anda gunakan dalam kode Anda. Saya pikir saya perlu melakukan lebih banyak pekerjaan untuk mengunggah file dan mengambil datanya tetapi… kerja bagus, Team Web!

Mengurai File

Saya hanya mencari di internet sebentar untuk melihat perpustakaan parsing CSV apa yang ada di luar sana, dan saya segera menemukan Papa Parse. Itu memiliki cukup banyak bintang dan aktivitas GitHub untuk saya berikan 👍.

// After the user submits the form...
// Parsing handled separately in a callback.
Papa.parse(currentFiles[0], parseConfig);

Yang perlu saya lakukan hanyalah meneruskan objek file yang saya ambil pada pengiriman formulir dan menyediakan panggilan balik di objek konfigurasi yang digunakan fungsi parse sebagai parameter. Saya tahu bahwa Papa Parse memiliki banyak fungsi yang belum saya jelajahi, namun saya senang karena Papa Parse sangat mudah digunakan dan memberi saya data header dan baris yang saya perlukan dalam format yang mudah diakses.

Membuat JSON…dan eval()?

Daging dan sayuran (daging dan kentang di negara bagian) aplikasi saya adalah cara file CSV diurai menjadi JSON. Saya memvisualisasikannya dalam struktur pohon yang saya gambar di awal postingan ini karena, dalam format tersebut, Anda dapat memindahkan organisasi dan membawa serta anak-anaknya. Anda pasti ingin membawa anak-anak Anda jika Anda pindah juga, bukan? Saya pikir Anda secara hukum harus melakukannya. 😝…membunuhnya.

Namun yang lebih serius, jika organisasi memiliki hubungan ini, tidak masuk akal bagi saya untuk mencantumkan induknya di bidang yang membuat file JSON terlihat sama dengan file CSV. Juga tidak masuk akal untuk menghindari pembuatan format yang lebih berbelit-belit setelah saya mencoba membuat struktur pohon asli dari satu file CSV dan gagal…dan terus gagal. Saya kesal dengan keterampilan perkembangan kekanak-kanakan saya.

Anda mungkin ingin duduk dulu sebelum saya menunjukkan kode berikut. Ia menggunakan fungsi eval() yang jahat. MALU, MALU! Kok bisa, bentak internet. Internet sebenarnya tidak menggonggong dan sepertinya mengatakan bahwa eval() tidak terlalu jahat untuk digunakan asalkan Anda melakukannya pada saat harga diri rendah dan kesedihan. StackOverflow memberitahuku begitu.

Saya juga berkonsultasi dengan Honey Badger yang terkenal dan berbakat, dan dia mengatakan kepada saya, “Honey Badger tidak peduli! Honey Badget menggunakan eval() sepanjang waktu!”

Sah.

Penggunaan saya atas eval berasal dari ketidakmampuan saya untuk mengetahui cara menetapkan nilai pada rantai suatu objek ketika saya tidak tahu apa sebenarnya elemen induknya pada saat penugasan. Bagi saya, penugasan variabel terjadi dalam satu baris kode dan rekursi masih merupakan implementasi yang sulit saya gunakan. Saya pikir…menulis kode…menulis kalimat…membuat goresan di papan tulis…berpikir lagi…melihat ke luar jendela. Lalu saya berpikir, persetan, saya akan menggunakan variabel variabel untuk menyelesaikan tugas saya.

Saya jauh lebih akrab dengan PHP, yang mengizinkan variabel variabel dengan menggunakan token variabel $ dua kali $$varString tetapi di JS, eval sepertinya satu-satunya solusi untuk itu, meskipun saya mungkin telah melihat cara lain untuk melakukan ini di StackOverflow. Saya tidak menggunakan variabel variabel di PHP, tapi solusi saya adalah menggunakan variabel eval dan variabel untuk membuat variabel penugasan dan kemudian menetapkan nilai akhir dalam objek bersarang dengan satu panggilan eval…yah, beberapa seperti yang akan Anda lihat.

Dalam potongan kode yang indah dan indah itu, setiap nilai header tingkat organisasi diperiksa untuk melihat apakah kosong. Baris file CSV selalu mendeklarasikan induknya dengan setidaknya satu nilai orgLevelHeaders kosong sehingga hanya nilai itulah yang perlu saya periksa guna mencari tahu di mana menempatkan data akhir untuk organisasi tertentu. Ketika evaluasi akhir dilakukan, varString berisi hierarki tingkat organisasi yang diperlukan untuk menetapkan data di dalamnya.

Saya yakin saya bisa melakukan ini dengan cara yang lebih baik, tapi saat membuat PoC saya tidak cenderung menghabiskan terlalu banyak waktu membersihkan kode sampai saya tahu bahwa arah yang saya ambil adalah arah yang benar. Karena itu, beri tahu saya seberapa besar kesalahan kode saya di bagian komentar.

Mengunduh File

Jika Anda tidak tahu cara mengunduh file dengan mengklik tombol di browser, saya akan menyertakan beberapa kode itu juga. Saya akan menghabiskan beberapa waktu untuk meneliti bagaimana melakukan ini, tetapi saya sudah menyalin dan menempelkannya…ahem, menemukan jawabannya…di proyek lain.

…Saya tidak bisa menjelaskan kodenya dengan baik, tapi sekali lagi MDN dapat memberi tahu Anda beberapa di antaranya seperti Blob. Pada dasarnya, Anda membuat gumpalan data yang diubah menjadi file yang dapat diunduh, membuat tautan sementara pada halaman, menyimulasikan klik pada tautan ke URL file, lalu menghapus tautan tersebut. Rupanya atribut download untuk link adalah fitur HTML5. Yang saya tahu hanyalah ini berfungsi di Chrome 🤷‍♂

Anda dapat menemukan kode lengkap untuk aplikasi tersebut di sini: https://github.com/alexfinnarn/directory_parser. Proyek ini memiliki readme hebat yang akan memberi tahu Anda cara kerja semuanya 😬.