Как загрузить URL файла изображения в indexedDB для рендеринга на странице - PullRequest
0 голосов
/ 05 сентября 2018

Цель состоит в том, чтобы при добавлении клиента я также хотел иметь возможность загружать изображение. На главной странице клиента будут перечислены все клиенты и уменьшенное изображение клиента.

В настоящее время, когда я загружаю изображение в indexedDB, оно не принимает правильный URL. В моем текущем учебном проекте, когда я загружаю изображение, оно загружает этот URL-адрес:

C:\fakepath\01-gel-nail-designs-thecuddl.jpg

Я не уверен, почему он продолжает давать C:\fakepath, который не является правильным путем, поэтому, когда он отображает на главной странице клиента, это просто битый заполнитель изображения.

Вот мой index.html:

 <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->


    <title>Customer Manager</title>

    <!-- Bootstrap core CSS -->
    <link href="css/bootstrap.min.css" rel="stylesheet">

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="../../assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="css/style.css" rel="stylesheet">
  </head>
  <body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Customer Manager v0.1</a>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="#">Customers <span class="sr-only">(current)</span></a></li>
            <li><a href="add.html">Add Customer</a></li>
            <li><a onclick="clearCustomers()" class="danger" href="#">Clear Customers</a></li>
          </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
          <h1 class="page-header">Customers</h1>
          <div class="table-responsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>#</th>
                  <th>Name</th>
                  <th>Email Address</th>
                  <th></th>
                </tr>
              </thead>
              <tbody id="customers">

              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
    <script src="js/bootstrap.min.js"></script>
    <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>

Вот мой add.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->


    <title>Add Customer</title>

    <!-- Bootstrap core CSS -->
    <link href="css/bootstrap.min.css" rel="stylesheet">

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="../../assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="css/style.css" rel="stylesheet">
  </head>
  <body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Customer Manager v0.1</a>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="#">Customers <span class="sr-only">(current)</span></a></li>
            <li><a href="add.html">Add Customer</a></li>
            <li><a class="danger" href="#">Clear Customers</a></li>
          </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
          <h1 class="page-header">Add Customer</h1>
          <form role="form" onsubmit="addCustomer()">
              <div class="form-group">
                <label>Customer Name</label>
                <input type="text" id="name" class="form-control" placeholder="Enter Name">
              </div>
              <div class="form-group">
                <label>Customer Email</label>
                <input type="email" id="email" class="form-control" placeholder="Enter Email">
              </div>
              <input type="file" id="imageSelector" multiple="multiple" />
              <button type="submit" class="btn btn-default">Add Customer</button>
        </form>
        </div>
      </div>
    </div>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
    <script src="js/bootstrap.min.js"></script>
    <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>

Вот мой main.js:

$(document).ready(function(){
    //Open database
    var request = indexedDB.open('customermanager',1);

    request.onupgradeneeded = function(e){
        var db = e.target.result;

        if(!db.objectStoreNames.contains('customers')){
              var os = db.createObjectStore('customers',{keyPath: "id", autoIncrement:true});
                //Create Index for Name
                os.createIndex('name','name',{unique:false});
        }
    }


    //Success
    request.onsuccess = function(e){
        console.log('Success: Opened Database...');
        db = e.target.result;
        //Show Customers
        showCustomers();
    }

    //Error
    request.onerror = function(){
        console.log('Error: Could Not Open Database...');
    }
});

//Add Customer
function addCustomer(){
    var name = $('#name').val();
    var email = $('#email').val();
    var image = $('#imageSelector').getAttribute('src');



    var transaction = db.transaction(["customers"],"readwrite");
    //Ask for ObjectStore
    var store = transaction.objectStore("customers");

    //Define Customer
    var customer = {
        name: name,
        email: email,
        image: image
    }

    //Perform the Add
    var request = store.add(customer);

    //Success
    request.onsuccess = function(e){
        window.location.href="index.html";
    }

    //Error
    request.onerror = function(e){
        alert("Customer was not added");
        console.log('Error', e.target.error.name);
    }
}

//Display Customers
function showCustomers(e){
    var transaction = db.transaction(["customers"],"readonly");
    //Ask for ObjectStore
    var store = transaction.objectStore("customers");
    var index = store.index('name');

    var output = '';
    index.openCursor().onsuccess = function(e){
        var cursor = e.target.result;
        if(cursor){
            output += "<tr id='customer_"+cursor.value.id+"'>";
            output += "<td>"+cursor.value.id+"</td>";
            output += "<td><span class='cursor customer' contenteditable='true' data-field='name' data-id='"+cursor.value.id+"'>"+cursor.value.name+"</span></td>";
            output += "<td><span class='cursor customer' contenteditable='true' data-field='email' data-id='"+cursor.value.id+"'>"+cursor.value.email+"</span></td>";
              output += "<td><img class='thumbnail' src='"+cursor.value.id+"'></img></td>";
            output += "<td><a onclick='removeCustomer("+cursor.value.id+")' href=''>Delete</a></td>";
            output += "</tr>";
            cursor.continue();
        }
        $('#customers').html(output);
    }
}

//Delete a Customer
function removeCustomer(id){
    var transaction = db.transaction(["customers"],"readwrite");
    //Ask for ObjectStore
    var store = transaction.objectStore("customers");

    var request = store.delete(id);

    //Success
    request.onsuccess = function(){
        console.log('Customer '+id+' Deleted');
        $('customer_'+id).remove();
    }

    //Error
    request.onerror = function(e){
        alert("The customer was not removed")
        console.log('Error', e.target.error.name);
    }
}

//Clear All Customers
function clearCustomers(){
    indexedDB.deleteDatabase('customermanager');
    window.location.href="index.html";
}

//Update Customers
$('#customers').on('blur','.customer',function(){
    //Newly entered text
    var newText = $(this).html();
    //Field
    var field = $(this).data('field');
    //Customer ID
    var id = $(this).data('id');

    //Get Transaction
    var transaction = db.transaction(["customers"],"readwrite");
    //Ask for ObjectStore
    var store = transaction.objectStore("customers");

    var request = store.get(id);

    request.onsuccess = function(){
        var data = request.result;
        if(field == 'name'){
           data.name = newText;
        } else if(field == 'email'){
            data.email = newText;
        }

        //Store Updated Text
        var requestUpdate = store.put(data);

        requestUpdate.onsuccess = function(){
            console.log('Customer field updated...');
        }

        requestUpdate.onerror = function(){
            console.log('Customer field NOT updated...');
        }
    }
});

Вот изображение того, как indexedDB выглядит в консоли, и как это выглядит в моем index.html:

first image

Вот изображение того, как выглядит мой add.html:

second image

Любое руководство будет с благодарностью.

ОБНОВЛЕНИЕ 1

Основываясь на некоторых дополнительных исследованиях, я не смогу делать то, что хочу, с кодом, который у меня есть, по соображениям безопасности, я не смогу найти истинный путь без использования других методов. Я пытаюсь найти способ реализовать пример по этой ссылке https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/.

1 Ответ

0 голосов
/ 06 сентября 2018

Это неполный ответ, только некоторые заметки. Если вы настаиваете на использовании indexedDB, вы, вероятно, захотите сохранить загруженные файлы в виде больших двоичных объектов в indexedDB. Далее вы хотите установить src изображения в URL-адрес большого объекта, используя URL.createObjectURL. Имейте в виду, что в некоторых браузерах возникают проблемы с хранением больших двоичных объектов, поэтому возможность их работы зависит от того, какие браузеры вы поддерживаете.

Вот примерный код, с которого можно начать:

addEventListener('DOMContentLoaded', event => {
  attachUploadHandler();
});

function attachUploadHandler() {
  const input = document.querySelector('#uploader');
  input.setAttribute('type', 'file');
  input.setAttribute('accept', 'image/png, image/gif, image/jpeg');
  input.onchange = onchange;
}

function openDb() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(name, version);
    request.onupgradeneeded = onupgradeneeded;
    request.onsuccess = _ => resolve(request.result);
    request.onerror = _ => reject(request.error);
  });
}

function onupgradeneeded(event) {
  const conn = event.target.result;
  conn.createObjectStore('store');
}

// Handle file uploader change event 
async function onchange(event) {
  const files = event.target.files;

  const conn = await openDb();
  await new Promise((resolve, reject) => {
    const tx = conn.transaction('store', 'readwrite');
    tx.oncomplete = resolve;
    tx.onerror = _ => reject(new Error('file storage error'));

    const store = tx.objectStore('store');

    for(const file of files) {
      store.put(file);
    }
  });
  conn.close();
}

Затем вы, возможно, захотите использовать вне строки ключи с хранилищем изображений, а затем сохранить идентификатор изображения в магазине покупателя. затем вы загружаете всех клиентов и для каждого клиента запрашиваете хранилище изображений для соответствующего изображения.

На данный момент я забыл, как делать внеплановые операции чтения / записи, так что вам придется это выяснить.

function getCustomers(conn) {
  return new Promise((resolve, reject) {
    const tx = conn.transaction(['customers', 'images']);
    tx.oncomplete = resolve(customers);
    const customer_store = tx.objectStore('customers');
    const image_store = tx.objectStore('images');

    function set_customer_image(customer, event) {
      customer.image_blob = event.target.result;
    }

    const customers_request = customer_store.getAll();
    customers_request.onsuccess = event => {
      const customers = customers_request.result;
      for(const customer of customers) {
        const image_request = image_store.get(customer.image_id);
        image_request.onsuccess = set_customer_image.bind(image_request, customer);          
      }
    };
  });
}

Затем при рендеринге уловка заключается в том, чтобы использовать URL.createObjectURL для каждого большого двоичного объекта и установить для него image_element.src.

function renderCustomers(customers) {
  const image_placeholder_url_string = 'customer-image-placeholder.gif';

  for(const customer of customers) {
     const tr = new HTMLTableRowElement();

     // now, the key part for the customer image cell
     const td = new HTMLTableCellElement();
     const image = new HTMLImageElement();
     if(customer.image_blob) {
       image.src = URL.createObjectURL(customer.image_blob);
     } else {
       image.src = image_placeholder_url_string;
     }

     td.appendChild(image);
     tr.appendChild(td);
  }
}
...