[Ruby] Well, let’s preview the image. ~part5~

3 minute read

Assumption

  • Use ruby on rails 6.0.0.
  • User functions are assumed to be introduced by devise.
  • All view files are in haml format.
  • By the way, I use MacBook Air (Retina, 13-inch, 2020).

Introduction

A synopsis of the previous time (part4). We were able to implement even the registration and editing functions for product information that includes multiple images. It seems that the work has been completed.

By the way, the introduction and procedures are detailed in <a href=”https://qiita.com/silvercrow222/items/55aeb5d13ec2bde305db”“>part1</a>, so please take a look.

Come on! Only the preview remains!

Preview

Well then, let’s start with js. It’s similar to what you do with forms.

Create a function for html generation and display the new form at the same time. If you delete the image, let’s make the preview disappear.

app/assets/javascripts/product.js


$(function() {
  // ~ omitted ~
  const buildImg = (index, url)=> {
    const html = `<img data-index="${index}" src="${url}" width="100px" height="100px">`;
    return html;
  }
  // ~ omitted ~
  $('#image-box').on('change','.file', function(e) {
    const targetIndex = $(this).parent().data('index');
    const file = e.target.files[0];
    const blobUrl = window.URL.createObjectURL(file);

    if (img = $(`img[data-index="${targetIndex}"]`)[0]) {
      img.setAttribute('src', blobUrl);
    } else {
      $('#image-box').append(buildFileField(fileIndex[0]));
      fileIndex.shift();
      fileIndex.push(fileIndex[fileIndex.length-1] + 1)
    }
  });
  // ~ omitted ~
  $('#image-box').on('click','.remove', function() (
    // ~ omitted ~
    $(`img[data-index="${targetIndex}"]`).remove();
  });
});

It’s been a long time, but it’s like this. I don’t think I’ll be prepared to do that because the middle part is complicated.

Let’s add explanations in order.

const buildImg = (index, url)=> {
    const html = `<img data-index="${index}" src="${url}" width="100px" height="100px">`;
    return html;

First of all, it is a function for generating html, but I think that it is okay because there is nothing particularly difficult. With the url passed as an argument, the image is displayed while specifying the size.

$('#image-box').on('change','.file', function(e) {
    // Get the unique index assigned to the form.
    const targetIndex = $(this).parent().data('index');
    // Get the URL of the image file on the web.
    const file = e.target.files[0];
    const blobUrl = window.URL.createObjectURL(file);
    // Conditional branch if there is an image with the corresponding index
    if (img = $(`img[data-index="${targetIndex}"]`)[0]) {
      // Replace the URL of the image obtained in the previous line.
      img.setAttribute('src', blobUrl);
    } else {
      $('#previews').append(buildImg(targetIndex, blobUrl));
      $('#image-box').append(buildFileField(fileIndex[0]));
      fileIndex.shift();
      fileIndex.push(fileIndex[fileIndex.length-1] + 1)

Next is the process when selecting an image. This is what it looks like.

The difficult thing is to get the URL on the 5th and 6th lines, but I’m not quite sure about this, so I’ll try to investigate it later. Please be assured that the operation itself will work with this.

By the way, the part after else has only added a preview display to the description that originally existed, so please see the previous part for details.

The reason we moved them below else is that in the previous state, even if you replaced the image, a new form was displayed. So I put these guys under else so that the form is added only when adding images.

  $(`img[data-index="${targetIndex}"]`).remove();

Last but not least, I’m just deleting the preview to match the delete button. That’s it.

Now that the js processing is complete, we will add a preview that should be displayed in advance on the editing screen.

haml:app/views/products/_form.html.haml


= form_with model: @product, local: true do |f|
  = f.text_field :name, placeholder:'name'
  #image-box
# previews
      -if @product.persisted?
        [email protected]_with_index do |image, i|
          = image_tag image.src.url, data: {index: i }, width: '100', height: '100'
= F.fields_for :images do |i|
      // ~ omitted ~
  = f.submit'SEND'

I added *product.persisted?. The image associated with product is fetched one by one by url and displayed using image_tag.

By the way, .each_with_index is a method that assigns one number at the same time as .each by setting two arguments.

Now, the preview function is completed. That means

Finally

Finally completed! !! It took quite a while, but I managed to finish. Whew.

Even though it is said to be completed, the only thing that could be done was the functionality, so after that I feel like slowly making markup.

However, all the contents of the specifications could be implemented. I’m sorry I wrote it for a long time even though I’m not really doing any difficult things.

I don’t think it’s there, but if you’ve read this to the end, thank you very much for the long time. I hope you find it helpful.