IndexedDB এর সাথে ডাটাবাইন্ডিং UI উপাদান

ভূমিকা

IndexedDB হল ক্লায়েন্ট সাইডে ডেটা সঞ্চয় করার একটি শক্তিশালী উপায়। আপনি যদি এখনও এটি না দেখে থাকেন তবে আমি আপনাকে এই বিষয়ে সহায়ক MDN টিউটোরিয়ালগুলি পড়তে উত্সাহিত করব৷ এই নিবন্ধটি API এবং বৈশিষ্ট্যগুলির কিছু প্রাথমিক জ্ঞান অনুমান করে। যদিও আপনি আগে IndexedDB দেখেননি, আশা করি এই নিবন্ধের ডেমো আপনাকে এটি দিয়ে কী করা যেতে পারে তার একটি ধারণা দেবে।

আমাদের ডেমো একটি কোম্পানির জন্য ধারণা ইন্ট্রানেট অ্যাপ্লিকেশনের একটি সহজ প্রমাণ। অ্যাপ্লিকেশনটি কর্মীদের অন্যান্য কর্মচারীদের জন্য অনুসন্ধান করার অনুমতি দেবে। একটি দ্রুত, স্ন্যাপিয়ার অভিজ্ঞতা প্রদানের জন্য, কর্মচারী ডাটাবেসটি ক্লায়েন্টের মেশিনে অনুলিপি করা হয় এবং IndexedDB ব্যবহার করে সংরক্ষণ করা হয়। ডেমোটি কেবলমাত্র একটি স্বয়ংসম্পূর্ণ-শৈলী অনুসন্ধান এবং একটি একক কর্মচারী রেকর্ডের প্রদর্শন সরবরাহ করে, তবে কী চমৎকার তা হল যে একবার এই ডেটা ক্লায়েন্টে উপলব্ধ হলে, আমরা এটিকে আরও একাধিক উপায়ে ব্যবহার করতে পারি। আমাদের অ্যাপ্লিকেশানকে কী করতে হবে তার একটি প্রাথমিক রূপরেখা এখানে।

  1. আমাদের একটি IndexedDB এর একটি উদাহরণ সেট আপ করতে হবে এবং শুরু করতে হবে। বেশিরভাগ অংশে এটি সহজবোধ্য, কিন্তু Chrome এবং Firefox উভয় ক্ষেত্রেই এটি কাজ করা কিছুটা কঠিন বলে প্রমাণিত হয়।
  2. আমাদের দেখতে হবে আমাদের কাছে কোন ডেটা আছে কিনা, আর না থাকলে ডাউনলোড করুন। এখন সাধারণত এটি AJAX কলের মাধ্যমে করা হবে। আমাদের ডেমোর জন্য আমরা একটি সাধারণ ইউটিলিটি ক্লাস তৈরি করেছি যাতে দ্রুত জাল ডেটা তৈরি করা যায়। অ্যাপ্লিকেশনটি কখন এই ডেটা তৈরি করছে তা সনাক্ত করতে হবে এবং ব্যবহারকারীকে ততক্ষণ পর্যন্ত ডেটা ব্যবহার করতে বাধা দিতে হবে। এটি এককালীন অপারেশন। পরের বার যখন ব্যবহারকারী অ্যাপ্লিকেশনটি চালাবেন, তখন এই প্রক্রিয়াটির মধ্য দিয়ে যেতে হবে না। একটি আরও উন্নত ডেমো ক্লায়েন্ট এবং সার্ভারের মধ্যে সিঙ্ক ক্রিয়াকলাপগুলি পরিচালনা করবে, তবে এই ডেমোটি UI দিকগুলিতে আরও বেশি ফোকাস করে৷
  3. যখন অ্যাপ্লিকেশন প্রস্তুত হয়, তখন আমরা IndexedDB-এর সাথে সিঙ্ক করতে jQuery UI এর স্বয়ংসম্পূর্ণ নিয়ন্ত্রণ ব্যবহার করতে পারি। যদিও স্বয়ংসম্পূর্ণ নিয়ন্ত্রণ মৌলিক তালিকা এবং ডেটার অ্যারেগুলির জন্য অনুমতি দেয়, এটিতে কোনও ডেটা উত্সের জন্য অনুমতি দেওয়ার জন্য একটি API রয়েছে। আমাদের IndexedDB ডেটার সাথে সংযোগ করতে আমরা কীভাবে এটি ব্যবহার করতে পারি তা আমরা প্রদর্শন করব।

শুরু হচ্ছে

আমরা এই ডেমোতে একাধিক অংশ পেয়েছি, তাই সহজভাবে জিনিসগুলি শুরু করতে, আসুন HTML অংশটি দেখি।

<form>
  <p>
    <label for="name">Name:</label> <input id="name" disabled> <span id="status"></span>
    </p>
</form>

<div id="displayEmployee"></div>

অনেক না, তাই না? এই UI এর তিনটি প্রধান দিক রয়েছে যা আমরা যত্ন করি। প্রথমটি হল ক্ষেত্র, "নাম" যা স্বয়ংসম্পূর্ণতার জন্য ব্যবহার করা হবে। এটি অক্ষম লোড হয় এবং জাভাস্ক্রিপ্টের মাধ্যমে পরে সক্রিয় করা হবে৷ এর পাশের স্প্যানটি ব্যবহারকারীকে আপডেট দেওয়ার জন্য প্রাথমিক বীজের সময় ব্যবহার করা হয়। অবশেষে, যখন আপনি অটোসাজেস্ট থেকে একজন কর্মী নির্বাচন করবেন তখন id displayEmployee সহ div ব্যবহার করা হবে।

এখন জাভাস্ক্রিপ্ট দেখে নেওয়া যাক। এখানে হজম করার মতো অনেক কিছু আছে তাই আমরা ধাপে ধাপে এটি নিয়ে যাব। সম্পূর্ণ কোডটি শেষে পাওয়া যাবে যাতে আপনি এটি সম্পূর্ণরূপে দেখতে পারেন।

প্রথমত - কিছু প্রিফিক্স সমস্যা রয়েছে যা আমাদেরকে IndexedDB সমর্থন করে এমন ব্রাউজারগুলির মধ্যে চিন্তা করতে হবে। এখানে মোজিলা ডকুমেন্টেশন থেকে কিছু কোড রয়েছে যা আমাদের অ্যাপ্লিকেশনের প্রয়োজনীয় মূল IndexedDB উপাদানগুলির জন্য সহজ উপনাম প্রদান করতে পরিবর্তিত হয়েছে।

window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;

এর পরে, কয়েকটি গ্লোবাল ভেরিয়েবল আমরা ডেমো জুড়ে ব্যবহার করব:

var db;
var template;

এখন আমরা jQuery নথি প্রস্তুত ব্লক দিয়ে শুরু করব:

$(document).ready(function() {
  console.log("Startup...");
  ...
});

আমাদের ডেমো কর্মীদের বিবরণ প্রদর্শন করতে Handlebars.js ব্যবহার করে। এটি পরে ব্যবহার করা হয় না, তবে আমরা এগিয়ে যেতে পারি এবং এখনই আমাদের টেমপ্লেট কম্পাইল করতে পারি এবং এটিকে বের করে আনতে পারি। আমরা একটি হ্যান্ডেলবার-স্বীকৃত টাইপ হিসাবে একটি স্ক্রিপ্ট ব্লক সেট আপ করেছি। এটি ভয়ানক অভিনব নয়, তবে গতিশীল HTML প্রদর্শন করা সহজ করে তোলে।

<h2>, </h2>
Department: <br/>
Email: <a href='mailto:'></a>

এটি আমাদের জাভাস্ক্রিপ্টে আবার কম্পাইল করা হয়েছে এভাবে:

//Create our template
var source = $("#employeeTemplate").html();
template = Handlebars.compile(source);

এখন আমাদের IndexedDB নিয়ে কাজ শুরু করা যাক। প্রথম - আমরা এটি খুলি।

var openRequest = indexedDB.open("employees", 1);

IndexedDB-তে একটি সংযোগ খোলার ফলে আমাদের ডেটা পড়তে এবং লিখতে অ্যাক্সেস পাওয়া যায়, কিন্তু আমরা তা করার আগে, আমাদের নিশ্চিত করতে হবে যে আমাদের কাছে একটি অবজেক্টস্টোর আছে। একটি অবজেক্টস্টোর একটি ডাটাবেস টেবিলের মতো। একটি ইনডেক্সডডিবিতে অনেকগুলি অবজেক্টস্টোর থাকতে পারে, প্রতিটিতে সম্পর্কিত বস্তুর সংগ্রহ রয়েছে। আমাদের ডেমো সহজ এবং শুধুমাত্র একটি অবজেক্টস্টোর প্রয়োজন যাকে আমরা "কর্মচারী" বলি৷ যখন প্রথমবারের জন্য indexedDB খোলা হয়, বা যখন আপনি কোডের সংস্করণ পরিবর্তন করেন, তখন আপগ্রেডেড একটি ইভেন্ট চালানো হয়। আমরা আমাদের অবজেক্টস্টোর সেটআপ করতে এটি ব্যবহার করতে পারি।

// Handle setup.
openRequest.onupgradeneeded = function(e) {

  console.log("running onupgradeneeded");
  var thisDb = e.target.result;

  // Create Employee
  if(!thisDb.objectStoreNames.contains("employee")) {
    console.log("I need to make the employee objectstore");
    var objectStore = thisDb.createObjectStore("employee", {keyPath: "id", autoIncrement: true});
    objectStore.createIndex("searchkey", "searchkey", {unique: false});
  }

};

openRequest.onsuccess = function(e) {
  db = e.target.result;

  db.onerror = function(e) {
    alert("Sorry, an unforseen error was thrown.");
    console.log("***ERROR***");
    console.dir(e.target);
  };

  handleSeed();
};

onupgradeneeded ইভেন্ট হ্যান্ডলার ব্লকে, আমরা অবজেক্ট স্টোরের নাম, অবজেক্ট স্টোরের একটি অ্যারে পরীক্ষা করি, এতে কর্মচারী আছে কিনা তা দেখতে। যদি না হয়, আমরা সহজভাবে এটা তাই করতে. CreateIndex কল গুরুত্বপূর্ণ। আমাদের অবশ্যই IndexedDB কে বলতে হবে, কীগুলির বাইরে, আমরা ডেটা পুনরুদ্ধার করতে ব্যবহার করব। আমরা সার্চকি নামে একটি ব্যবহার করব। এটি একটি বিট ব্যাখ্যা করা হয়.

প্রথমবার যখন আমরা স্ক্রিপ্ট চালাব তখন onungradeneeded ইভেন্টটি স্বয়ংক্রিয়ভাবে চলবে। এটি সম্পাদিত হওয়ার পরে, বা ভবিষ্যতের দৌড়ে এড়িয়ে যাওয়ার পরে, onsuccess হ্যান্ডলার চালানো হয়। আমরা একটি সাধারণ (এবং কুৎসিত) ত্রুটি হ্যান্ডলারকে সংজ্ঞায়িত করেছি এবং তারপরে আমরা handleSeed কল করি।

তাই আমরা এগিয়ে যাওয়ার আগে, আসুন এখানে কী ঘটছে তা দ্রুত পর্যালোচনা করি। আমরা ডাটাবেস খুলি। আমরা আমাদের বস্তুর দোকান বিদ্যমান কিনা তা পরীক্ষা করে দেখুন। যদি এটি না হয়, আমরা এটি তৈরি করি। অবশেষে, আমরা handleSeed নামে একটি ফাংশন কল করি। এখন আমাদের ডেমোর ডেটা সিডিং অংশে মনোযোগ দেওয়া যাক।

কিছু তথ্য দিন!

এই নিবন্ধের ভূমিকায় উল্লিখিত হিসাবে, এই ডেমোটি একটি ইন্ট্রানেট শৈলী অ্যাপ্লিকেশন পুনরায় তৈরি করছে যা সমস্ত পরিচিত কর্মচারীদের একটি অনুলিপি সংরক্ষণ করতে হবে৷ সাধারণত এর মধ্যে একটি সার্ভার-ভিত্তিক API তৈরি করা জড়িত যা কর্মচারীদের সংখ্যা ফেরত দিতে পারে এবং আমাদের জন্য রেকর্ডের ব্যাচগুলি পুনরুদ্ধার করার একটি উপায় প্রদান করতে পারে। আপনি একটি সাধারণ পরিষেবা কল্পনা করতে পারেন যা একটি শুরু গণনা সমর্থন করে এবং একবারে 100 জনকে ফেরত দেয়। এটি ব্যাকগ্রাউন্ডে অ্যাসিঙ্ক্রোনাসভাবে চলতে পারে যখন ব্যবহারকারী অন্যান্য জিনিসগুলি বন্ধ করে থাকে।

আমাদের ডেমোর জন্য, আমরা কিছু সহজ করি। আমরা দেখতে পাই আমাদের IndexedDB-তে কতগুলি বস্তু আছে, যদি থাকে। একটি নির্দিষ্ট সংখ্যার নিচে হলে, আমরা কেবল জাল ব্যবহারকারী তৈরি করব। অন্যথায় আমরা বীজ অংশের সাথে সম্পন্ন বলে বিবেচিত এবং ডেমোর স্বয়ংসম্পূর্ণ অংশ সক্ষম করতে পারি। এর handleSeed তাকান.

function handleSeed() {
  // This is how we handle the initial data seed. Normally this would be via AJAX.

  db.transaction(["employee"], "readonly").objectStore("employee").count().onsuccess = function(e) {
    var count = e.target.result;
    if (count == 0) {
      console.log("Need to generate fake data - stand by please...");
      $("#status").text("Please stand by, loading in our initial data.");
      var done = 0;
      var employees = db.transaction(["employee"], "readwrite").objectStore("employee");
      // Generate 1k people
      for (var i = 0; i < 1000; i++) {
         var person = generateFakePerson();
         // Modify our data to add a searchable field
         person.searchkey = person.lastname.toLowerCase();
         resp = employees.add(person);
         resp.onsuccess = function(e) {
           done++;
           if (done == 1000) {
             $("#name").removeAttr("disabled");
             $("#status").text("");
             setupAutoComplete();
           } else if (done % 100 == 0) {
             $("#status").text("Approximately "+Math.floor(done/10) +"% done.");
           }
         }
      }
    } else {
      $("#name").removeAttr("disabled");
      setupAutoComplete();
    }
  };
}

প্রথম লাইনটি একটু জটিল কারণ আমরা একাধিক অপারেশন একে অপরের সাথে শৃঙ্খলিত করেছি, তাই আসুন এটি ভেঙে ফেলা যাক:

db.transaction(["employee"], "readonly");

এটি একটি নতুন পঠনযোগ্য লেনদেন তৈরি করে। IndexedDB এর সাথে সমস্ত ডেটা ক্রিয়াকলাপের জন্য কিছু ধরণের লেনদেনের প্রয়োজন হয়।

objectStore("employee");

কর্মচারী বস্তুর দোকান পান.

count()

গণনা API চালান - যা আপনি অনুমান করতে পারেন - একটি গণনা সম্পাদন করে।

onsuccess = function(e) {

এবং হয়ে গেলে - এই কলব্যাকটি চালান। কলব্যাকের ভিতরে আমরা ফলাফলের মান পেতে পারি যা বস্তুর সংখ্যা। যদি গণনা শূন্য হয়, তাহলে আমরা আমাদের বীজ প্রক্রিয়া শুরু করি।

আমরা পূর্বে উল্লেখিত স্ট্যাটাস ডিভ ব্যবহার করে ব্যবহারকারীকে একটি বার্তা দিতে চাই যে আমরা ডেটা পেতে শুরু করতে যাচ্ছি। IndexedDB-এর অ্যাসিঙ্ক্রোনাস প্রকৃতির কারণে, আমরা একটি সাধারণ পরিবর্তনশীল সেট আপ করেছি, সম্পন্ন হয়েছে, যা সংযোজনগুলিকে ট্র্যাক করবে। আমরা লুপ ওভার এবং জাল মানুষ সন্নিবেশ. সেই ফাংশনের উত্সটি ডাউনলোডে উপলব্ধ, তবে এটি এমন একটি বস্তু ফেরত দেয় যা দেখতে এইরকম:

{
  firstname: "Random Name",
  lastname: "Some Random Last Name",
  department: "One of 8 random departments",
  email: "first letter of firstname+lastname@fakecorp.com"
}

নিজেই, এটি একজন ব্যক্তির সংজ্ঞায়িত করার জন্য যথেষ্ট। কিন্তু আমাদের ডেটা অনুসন্ধান করতে সক্ষম হওয়ার জন্য আমাদের একটি বিশেষ প্রয়োজন রয়েছে৷ IndexedDB কেস-অসংবেদনশীল পদ্ধতিতে আইটেমগুলি সন্ধান করার উপায় প্রদান করে না। অতএব, আমরা শেষনাম ক্ষেত্রের একটি অনুলিপি একটি নতুন সম্পত্তি, সার্চকিতে তৈরি করি। আপনি যদি মনে রাখবেন, এই কী যা আমরা বলেছিলাম যে আমাদের ডেটার জন্য একটি সূচক হিসাবে তৈরি করা উচিত।

// Modify our data to add a searchable field
person.searchkey = person.lastname.toLowerCase();

যেহেতু এটি একটি ক্লায়েন্ট-নির্দিষ্ট পরিবর্তন, এটি এখানে ব্যাক-এন্ড সার্ভারের (বা আমাদের ক্ষেত্রে, কাল্পনিক ব্যাক-এন্ড সার্ভারের) বিপরীতে করা হয়েছে।

একটি পারফরম্যান্ট ফ্যাশনে ডাটাবেস সংযোজন সঞ্চালনের জন্য, আপনার সমস্ত ব্যাচ করা লেখার জন্য লেনদেনটি পুনরায় ব্যবহার করা উচিত। আপনি যদি প্রতিটি লেখার জন্য একটি নতুন লেনদেন তৈরি করেন, ব্রাউজারটি প্রতিটি লেনদেনের জন্য একটি ডিস্ক লেখার কারণ হতে পারে, এবং এটি অনেকগুলি আইটেম যুক্ত করার সময় আপনার কার্যক্ষমতাকে ভয়ঙ্কর করে তুলবে ("1000টি বস্তু লিখতে 1 মিনিট মনে করুন"-ভয়ংকর)৷

একবার বীজ হয়ে গেলে, আমাদের আবেদনের পরবর্তী অংশটি ফায়ার করা হয় - সেটআপঅটোকমপ্লিট।

স্বয়ংসম্পূর্ণ তৈরি করা হচ্ছে

এখন মজার অংশের জন্য - jQuery UI স্বয়ংসম্পূর্ণ প্লাগইন এর সাথে হুক আপ করুন। বেশিরভাগ jQuery UI এর মতো, আমরা একটি মৌলিক HTML উপাদান দিয়ে শুরু করি এবং এটিতে একটি কনস্ট্রাক্টর পদ্ধতি কল করে এটিকে উন্নত করি। আমরা সেটআপঅটোকমপ্লিট নামক একটি ফাংশনে পুরো প্রক্রিয়াটিকে বিমূর্ত করেছি। চলুন এখন যে কোড তাকান.

function setupAutoComplete() {

  //Create the autocomplete
  $("#name").autocomplete({
    source: function(request, response) {

      console.log("Going to look for "+request.term);

      $("#displayEmployee").hide();

      var transaction = db.transaction(["employee"], "readonly");
      var result = [];

      transaction.oncomplete = function(event) {
        response(result);
      };

      // TODO: Handle the error and return to it jQuery UI
      var objectStore = transaction.objectStore("employee");

      // Credit: http://stackoverflow.com/a/8961462/52160
      var range = IDBKeyRange.bound(request.term.toLowerCase(), request.term.toLowerCase() + "z");
      var index = objectStore.index("searchkey");

      index.openCursor(range).onsuccess = function(event) {
        var cursor = event.target.result;
        if(cursor) {
          result.push({
            value: cursor.value.lastname + ", " + cursor.value.firstname,
            person: cursor.value
          });
          cursor.continue();
        }
      };
    },
    minLength: 2,
    select: function(event, ui) {
      $("#displayEmployee").show().html(template(ui.item.person));
    }
  });

}

এই কোডের সবচেয়ে জটিল অংশ হল উৎস সম্পত্তি তৈরি করা। jQuery UI এর স্বয়ংসম্পূর্ণ নিয়ন্ত্রণ আপনাকে একটি উৎস সম্পত্তি সংজ্ঞায়িত করতে দেয় যা যেকোনো সম্ভাব্য প্রয়োজন মেটাতে কাস্টমাইজ করা যেতে পারে - এমনকি আমাদের IndexedDB ডেটাও। API আপনাকে অনুরোধ প্রদান করে (মূলত যা ফর্ম ফিল্ডে টাইপ করা হয়েছিল) এবং একটি প্রতিক্রিয়া কলব্যাক। সেই কলব্যাকে ফলাফলের একটি অ্যারে পাঠানোর জন্য আপনি দায়ী৷

আমরা প্রথম জিনিসটি প্রদর্শন এমপ্লয়ি ডিভটি লুকাই। এটি একটি পৃথক কর্মচারী প্রদর্শন করতে এবং যদি একটি পূর্বে লোড আপ করা হয়, এটি পরিষ্কার করতে ব্যবহৃত হয়। এখন আমরা অনুসন্ধান শুরু করতে পারেন.

আমরা একটি শুধুমাত্র পঠনযোগ্য লেনদেন, ফলাফল নামক একটি অ্যারে এবং একটি অসম্পূর্ণ হ্যান্ডলার তৈরি করে শুরু করি যা ফলাফলটিকে স্বয়ংসম্পূর্ণ নিয়ন্ত্রণে পাস করে।

আমাদের ইনপুটের সাথে মেলে এমন আইটেমগুলি খুঁজে পেতে, আসুন স্ট্যাকওভারফ্লো ব্যবহারকারী ফং-ওয়ান চাউ-এর একটি টিপ ব্যবহার করি: আমরা একটি নিম্ন প্রান্তের সীমানা হিসাবে ইনপুটের উপর ভিত্তি করে একটি সূচক পরিসর ব্যবহার করি এবং ইনপুট প্লাস z অক্ষরটি একটি উচ্চ পরিসরের সীমানা হিসাবে ব্যবহার করি . উল্লেখ্য, আমরা শব্দটিকে ছোট হাতের হাতের অক্ষরের ডেটার সাথে মেলে যা আমরা প্রবেশ করিয়েছি।

একবার হয়ে গেলে - আমরা একটি কার্সার খুলতে পারি (একটি ডাটাবেস ক্যোয়ারী চালানোর মতো এটি মনে করুন) এবং ফলাফলগুলি পুনরাবৃত্তি করতে পারি। jQuery UI এর স্বয়ংসম্পূর্ণ নিয়ন্ত্রণ আপনাকে আপনার পছন্দসই যেকোনো ধরনের ডেটা ফেরত দিতে দেয়, তবে ন্যূনতম একটি মান কী প্রয়োজন। আমরা নামের একটি সুন্দর বিন্যাস সংস্করণ মান সেট. আমরা সম্পূর্ণ ব্যক্তি ফেরত. আপনি কেন এক সেকেন্ডের মধ্যে দেখতে পাবেন. প্রথমত, এখানে স্বয়ংসম্পূর্ণ কর্মের একটি স্ক্রিন শট রয়েছে৷ আমরা jQuery UI এর জন্য Vader থিম ব্যবহার করছি।

স্বয়ংক্রিয়ভাবে, আমাদের IndexedDB ম্যাচগুলির ফলাফলগুলি স্বয়ংসম্পূর্ণে ফিরিয়ে দেওয়ার জন্য এটি যথেষ্ট। তবে আমরা যখন একটি নির্বাচন করা হয় তখন ম্যাচের একটি বিশদ দৃশ্য দেখানোকে সমর্থন করতে চাই। স্বয়ংসম্পূর্ণ তৈরি করার সময় আমরা একটি নির্বাচিত হ্যান্ডলার নির্দিষ্ট করেছি যা আগে থেকে হ্যান্ডেলবার টেমপ্লেট ব্যবহার করে।