Try to implement tagging function using rails and js

Let's implement the tagging function with rails, and let's do advanced tagging with JavaScript in the second half

スクリーンショット 2020-12-18 14.36.29.png

This time, I would like to implement the function that allows you to enter tags like this and the function that predictive conversion is displayed below each time you enter a tag!

In the image, if you type "acid" in the tag input form, "sourness" is displayed below as a predictive conversion. However, since the browser is smart, the browser also outputs predictive conversion, but ... lol

Execute the following command

Terminal

% cd ~/projects

% rails _6.0.0_ new tagtweet -d mysql

% cd tagtweet
Database creation

Before creating the database, let's change the encoding setting described in database.yml.

config/database.yml

default: &default
  adapter: mysql2
  # encoding: utf8mb4
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

Then create a database

Terminal

rails db:create

so

Created database 'tagtweet_development' Created database 'tagtweet_test'

Is created

Database design

Since tweet and tag have a many-to-many relationship, Of the intermediate table The point is to create a ** tweet_tag_relations table **

Create a model

Terminal

% rails g model tweet
% rails g model tag
% rails g model tweet_tag_relation

Edit migration

db/migrate/20XXXXXXXXXXXX_create_tweets.rb

class CreateTweets < ActiveRecord::Migration[6.0]
  def change
    create_table :tweets do |t|
      t.string :message, null:false
      #Added messege column
      t.timestamps
    end
  end
end

db/migrate/20XXXXXXXXXXXX_create_tags.rb

class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :name, null:false, uniqueness: true 
      #Add name column
      t.timestamps
    end
  end
end

This time, we'll set a constraint of "uniqueness: true" to avoid duplicate tag names.

db/migrate/20XXXXXXXXXXXX_create_tweet_tag_relations.rb


class CreateTweetTagRelations < ActiveRecord::Migration[6.0]
  def change
    create_table :tweet_tag_relations do |t|
      t.references :tweet, foreign_key: true
      t.references :tag, foreign_key: true
      t.timestamps
    end
  end
end

In the tweet_tag_relations table, the information in the "tweets table" and "tags table" is referenced, so "foreign_key: true" is used.

Terminal

rails db:migrate
Form an association of case models

tweet.rb

class Tweet < ApplicationRecord

  has_many :tweet_tag_relations
  has_many :tags, through: :tweet_tag_relations

end

tag.rb

class Tag < ApplicationRecord

  has_many :tweet_tag_relations
  has_many :tweets, through: :tweet_tag_relations

end

tweet_tag_relation.rb

class TweetTagRelation < ApplicationRecord

  belongs_to :tweet
  belongs_to :tag

end
Let's set up the routing!

routes.rb

Rails.application.routes.draw do
 root to: 'tweets#index'
 resources :tweets, only: [:new, :create]
end

Specifications of this app

When you tweet something, we aim to have a specification in which "tweet" and "tag" are saved at the same time. Form objects are useful for such implementations.

Form object

Form objects are tools used to update multiple models in a single form submission. You can treat your own class like a model. This Form object can be used by loading a module called "ActiveModel :: Model".

ActiveModel::Model

"ActiveModel :: Model" is a tool that allows you to use helper methods such as "form_for" and "render" as in ActiveRecord. You will also be able to use the "Model Name Survey" and "Validation" functions.

Introduce From object

First, let's create tweets_tag.rb in the models directory

The layout is app/models/tweets_tag.rb.

tweets_tag.rb

class TweetsTag

  include ActiveModel::Model
   # include ActiveModel::Create a From object by describing a Model
  attr_accessor :message, :name
#Create virtual attributes that can be both getter and setter roles

# :First of all, it is ok to understand that you can save it by writing the column you want to save such as name

  with_options presence: true do
    validates :message
    validates :name
  end

  def save
    tweet = Tweet.create(message: message)
    tag = Tag.create(name: name)

    TweetTagRelation.create(tweet_id: tweet.id, tag_id: tag.id)
  end

#Describe the process to save the value in the case table in the save method

end

Since the uniqueness constraint needs to be set for each model, let's describe it in the tag model.

tag.rb

class Tag < ApplicationRecord

  has_many :tweet_tag_relations
  has_many :tweets, through: :tweet_tag_relations

  validates :name, uniqueness: true
end
Create a controller and edit it

Terminal

% rails g controller tweets

tweets_controller.rb

class TweetsController < ApplicationController

  def index
    @tweets = Tweet.all.order(created_at: :desc)
  end

  def new
    @tweet = TweetsTag.new
  end

  def create
    @tweet = TweetsTag.new(tweet_params)
    if @tweet.valid?
      @tweet.save
      return redirect_to root_path
    else
      render "new"
    end
  end

  private

  def tweet_params
    params.require(:tweets_tag).permit(:message, :name)
  end

end

I am using the new method for the "Form object".

I am using the save method defined in the From object

Create view

tweets/index.html.erb

<div class="header">
  <div class="inner-header">
    <h1 class="title">
     TagTweet
    </h1>
    <li class='new-post'>
      <%= link_to "New Post", new_tweet_path, class:"post-btn"%>
    </li>
  </div>
</div>

<div class="main">
  <div class="message-wrap">
    <% @tweets.each do |tweet|%>
      <div class="message">
        <p class="text">
          <%= tweet.message %>
        </p>
        <ul class="tag">
          <li class="tag-list">
            <%tweet.tags.each do |tag| %>
              #<%=tag.name%>
            <%end%>
          </li>
        </ul>
      </div>
    <%end%>
  </div>
</div>

tweets/new.html.erb

<%= form_with model: @tweet, url: tweets_path, class:'form-wrap', local: true do |f| %>
  <div class='message-form'>
    <div class="message-field">
      <%= f.label :message,  "Tweet" %>
      <%= f.text_area :message, class:"input-message" %>
    </div>
    <div class="tag-field", id='tag-field'>
      <%= f.label :name, "tag" %>
      <%= f.text_field :name, class:"input-tag" %>
    </div>
    <div id="search-result">
    </div>
  </div>
  <div class="submit-post">
    <%= f.submit "Send", class: "submit-btn" %>
  </div>
<% end %>

CSS omitted! !! !!

Edit tweets_tag.rb

tweets_tag.rb

class TweetsTag

  include ActiveModel::Model
  attr_accessor :message, :name

  with_options presence: true do
    validates :message
    validates :name
  end

  def save
    tweet = Tweet.create(message: message)
    tag = Tag.where(name: name).first_or_initialize
    tag.save

    TweetTagRelation.create(tweet_id: tweet.id, tag_id: tag.id)
  end

end
    tag = Tag.where(name: name).first_or_initialize
   

I will explain

Use the first_or_initialize method with the where method. where method By specifying the condition in the argument part like model .where (condition), you can get the "instance of the record that matches the condition" in the form of an array. Be sure to include the "column to be searched" in the argument condition and describe the conditional expression. If there is a record of the condition searched by where, an instance of that record is returned, otherwise a new instance is added. It is a method to make

** For now, the implementation of tagged tweets is complete ** ** If you want to tag tags that have already been saved in the database, it will be a more convenient application if there is a search function that can display tags that match the input characters as candidates during input **

Implemented sequential search function

With the sequential search function, if the tag "rails" already exists in the database, when the character "r" is entered, "rails" that matches the character "r" is displayed on the screen in real time as a candidate. A common guy to do When implementing by programming, it seems to be called ** incremental search **

Let's say that we should implement it,

application.js


require("@rails/ujs").start()
// require("turbolinks").start() //Comment out this line
require("@rails/activestorage").start()
require("channels")

If you do not comment out the above line, the event set in js may not fire, so it is safe to comment out

Preparing to implement incremental search

tweets_controller


class TweetsController < ApplicationController

#abridgement

  def search
    return nil if params[:keyword] == ""
    tag = Tag.where(['name LIKE ?', "%#{params[:keyword]}%"] )
    render json:{ keyword: tag }
  end


And define search actions

The LIKE clause is used when searching for ambiguous strings and is used with the where method.

% Contains any string, including blank strings

In short, based on the value received in params [: keyword], either the condition matches in the name column, or the one searched in the tag table is assigned to tag.

It is in json format, keyword is the key, tag is the value, and the result is returned to js.

Set up routing

routes.rb

Rails.application.routes.draw do
  root to: 'tweets#index'
  resources :tweets, only: [:index, :new, :create] do
    collection do
      get 'search'
    end
  end
end

Nesting (nesting) routing allows this parent-child relationship to be represented by routing.

collection and member

collections and members can be used when configuring routing. It allows you to optionally customize the URL of the generated routing and the controller to be executed.

The difference is that collection does not have: id in the routing, and member has: id.

In the case of this search function, it is not necessary to specify the: id like the detail page to go to a specific page, so let's set the routing using collection

Let's create tag.js

How to create tag.js for app/javascript/packs

application.js

Let's edit as follows to load tag.js

require("@rails/ujs").start()
// require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("./tag")

Anyone who has done a good curriculum up to this point should be able to understand it normally, but from now on I will explain what is not explained in the curriculum!

tag.js

if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
    console.log("Loading completed");
  });
};

location.pathname gets the URL of the current page, .match returns the matching result of the string passed as an argument In other words, the event fires when you are currently in tweets/new!

document is the whole html element addEventListener executes various event processing

DOMContentLoaded is when the web page has finished loading

That is, execute the event when the entire html element is loaded

OK when "Loading completed" is displayed on the console

Get the information you need to search for tags

tag.js

if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
    const inputElement = document.getElementById("tweets_tag_name");
    inputElement.addEventListener("keyup", () => {
      const keyword = document.getElementById("tweets_tag_name").value;
    });
  });
};

Get the html element with id tweets_tag_name and assign it to InputElement

** Be careful here! !! ** **

Granting id by form_with

Was there an element with the id that was tweets_tag_name? ??

tweets/new.html.erb

<%= form_with model: @tweet, url: tweets_path, class:'form-wrap', local: true do |f| %>
  <div class='message-form'>
    <div class="message-field">
      <%= f.label :message,  "Tweet" %>
      <%= f.text_area :message, class:"input-message" %>
    </div>
    <div class="tag-field", id='tag-field'>
      <%= f.label :name, "tag" %>
      <%= f.text_field :name, class:"input-tag" %>
    </div>
    <div id="search-result">
    </div>
  </div>
  <div class="submit-post">
    <%= f.submit "Send", class: "submit-btn" %>
  </div>
<% end %>

Also, index.html.erb doesn't have such an id. .. .. .. ..

But why can I get it? From the conclusion

** Because form_with will give you an id without permission **

More specifically, for example

form_with model: @tweet

tweets_controller

so


def new
 @tweet = TweetsTag.new
end

Is defined as

First, the id becomes ** tweet_tag **

And

** drinks/new.html.erb **

      <%= f.label :name, "tag" %>
      <%= f.text_field :name, class:"input-tag" %>

: name is

Attach to ** tweet_tag **, ** tweet_tag_name **

The id is generated! !!

The opinion is reasonable, "I can't believe who said where!" Check with the validation tool to see if form_with actually generated the id

スクリーンショット 2020-12-13 6.43.28.png

In the place of the message to tweet the tweet

An id called ** tweets_tag_messages ** was generated, and that was <%= f.text_area :message, class:"input-message" %>

Is given to.

Where to tag

An id called ** tweets_tag_name ** is generated, which is

  <%= f.text_field :name, class:"input-tag" %>

Is given to.

** id is given by form_with! !! !! ** **

Please keep that in mind

Now you have the input form

Check the contents of the variable keyword

app/javascript/packs/tag.js

if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
    const inputElement = document.getElementById("tweets_tag_name");
// form_Get the input form itself based on the id generated by with
    inputElement.addEventListener("keyup", () => {
//Event fire when keyboard key is released from input form
      const keyword = document.getElementById("tweets_tag_name").value;
// .By setting value, the value entered in the input form can be retrieved.
//Get the value actually entered and enter it in keyword
      console.log(keyword);
    });
  });
};

At this point, let's fill out the form. It is ok if the entered characters can be output to the console.

Generate XMLHttpRequest object

packs/tag.js


if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
    const inputElement = document.getElementById("tweets_tag_name");
    inputElement.addEventListener("keyup", () => {
      const keyword = document.getElementById("tweets_tag_name").value;
      const XHR = new XMLHttpRequest();
    })
  });
};

const XHR = new XMLHttpRequest (); Create an instance using the XMLHttpRequest object and assign it to the variable XHR Let's create the XMLHttpRequest object needed for asynchronous communication. You can send any HTTP request by using the XMLHttpRequest object.

Define request using open method

tag.js


if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
    const inputElement = document.getElementById("tweets_tag_name");
    inputElement.addEventListener("keyup", () => {
      const keyword = document.getElementById("tweets_tag_name").value;
      const XHR = new XMLHttpRequest();
      XHR.open("GET", `search/?keyword=${keyword}`, true);
    XHR.responseType = "json";
      XHR.send();
    })
  });
};

  XHR.open("GET", `search/?keyword=${keyword}`, true);

Specify the HTTP method as the first argument of the open method, the URL as the second argument, and true as the third argument to indicate that it is asynchronous communication.

The reason why such a URL is specified is,

This URL is called the query parameter, like http://sample.jp/?name=tanaka, A URL parameter that spells information after the "?". The structure after "?" Is **? = **.

This time, it is not necessary to identify tweets by: id, so specify the query parameter.

** Why is search omitted in the URL when I want to run drinks # search **

Because the path can be specified relatively based on the directory one level above the specified path.

For example, the path specified this time is search/keyword = hogehoge And the directory above is tweets, so It seems that it will complement the directory one level higher without permission. .. .. ..

Now you can run Drinks # search

I thought,


 XHR.responseType = "json";

Let's specify the json format as the format of the data returned from the controller by writing

And finally!


XHR.send();

Let's write and send a request.

Every time something is entered in the tag input form, the rails search action moves!

Receive the response from the server side

Let's receive the data returned as a response when the server-side processing is successful. Use the response property to receive the data.

tag.js

if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
#abridgement
      XHR.send();
      XHR.onload = () => {
        const tagName = XHR.response.keyword;
      };
    });
  });
};
const tagName = XHR.response.keyword;

Receives the data returned as a response and assigns it to the variable tagName when the server-side processing is successful. Use the response property to receive the data.

Let's describe the process to display the tag

スクリーンショット 2020-12-18 14.36.29.png

In this way, let's display them in order below

There are four steps to display the tag.

  1. Get the place to display the tag

I'm getting an element with an id name called search-result

  1. Get the location to store the tag name.

The element for displaying the tag is generated using the createElement method. The tag name of the search result is specified for the generated element.

  1. Insert a tag in element 2

The element prepared in 2 is inserted in the element of 1. It uses the innerHTML property and the appendChild method, respectively.

  1. Repeat steps 2 and 3 as long as there are search results

Iterative processing is performed using forEach

tag.js

      XHR.send();
      XHR.onload = () => {
        const tagName = XHR.response.keyword;
        const searchResult = document.getElementById("search-result");
          tagName.forEach((tag) => {
          //The reason for using forEach is the rails search action
          //So, I will put out multiple tags that got caught in the search
          //Because in some cases
          const childElement = document.createElement("div");
          // 2.Creating an element to display the tag
          //As the name suggests,Method to create element
         

          childElement.setAttribute("class", "child");
          childElement.setAttribute("id", tag.id);
          //Class in the created div tag,Give id
          //I'm using the tag of a local variable created by forEach here

          childElement.innerHTML = tag.tag_name;
          // <div>tagname</div>Feeling
          //With innerHTML,
          //Replace, rewrite, or insert the contents
          // 3.The tag of the tag returned from the server side_name
          //Image to put in childElement
           searchResult.appendChild(childElement);
          //html search-As a child element of result
          //childElements line up

          //I will display it for the first time here
          
        });
      };
    });
  });
};

new.html.erb


<%= form_with model: @tweet, url: tweets_path, class:'form-wrap', local: true do |f| %>
  <div class='message-form'>
    <div class="message-field">
      <%= f.label :message,  "Tweet" %>
      <%= f.text_area :message, class:"input-message" %>
    </div>
    <div class="tag-field", id='tag-field'>
      <%= f.label :name, "tag" %>
      <%= f.text_field :name, class:"input-tag" %>
    </div>
    <div id="search-result">
    </div>
  </div>
  <div class="submit-post">
    <%= f.submit "Send", class: "submit-btn" %>
  </div>
<% end %>

so

    <div id="search-result">
    </div>

,

tag.js


  const searchResult = document.getElementById("search-result");

Get it with, perform the above processing, and display the candidates below every time you enter something

Let's make sure that the tag name you clicked is entered in the form

Specify the click event for the element displaying the tag. When clicked, enter the tag name in the form and remove the element that displays the tag

tag.js


      XHR.send();
      XHR.onload = () => {
        const tagName = XHR.response.keyword;
        const searchResult = document.getElementById("search-result");
        tagName.forEach((tag) => {
          const childElement = document.createElement("div");
          childElement.setAttribute("class", "child");
          childElement.setAttribute("id", tag.id);
          childElement.innerHTML = tag.name;
          searchResult.appendChild(childElement);
          const clickElement = document.getElementById(tag.id);
          clickElement.addEventListener("click", () => {
            document.getElementById("tweets_tag_name").value = clickElement.textContent;
            clickElement.remove();
          });
        });
      };
    });
  });
};

The whole picture looks like this

          const clickElement = document.getElementById(tag.id);
//Get the elements of the predictive conversion column that are displayed in order under the tag input form generated earlier
          clickElement.addEventListener("click", () => {
//Click the acquired element to fire the event
            document.getElementById("tweets_tag_name").value = clickElement.textContent;
// tweets_tag_name is form_The id given to the input form with with
//Get input form

//further.By setting it to value, it was actually entered
//Get value

//clickElement has the name of the tag
// .You can get the name of the tag with textContent

//Now when you click on the tag part, the name of the tag will be
//Enter the form
            clickElement.remove();

//Only the clicked tag disappears

However, the same tag will continue to be displayed many times. The reason for this is that every time an incremental search is performed, the latest search results are added while keeping the previous search results. Make sure to delete the previous search results each time an incremental search is performed.

Let's delete the previous result search

By specifying an empty character string for the innerHTML property of the element in which the search result is inserted, the displayed tag will be deleted.

tag.js


if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
#abridgement
      XHR.send();
      XHR.onload = () => {
        const tagName = XHR.response.keyword;
        const searchResult = document.getElementById("search-result");
        searchResult.innerHTML = "";

        //In the innerHTML property of the element inserting the search result
        //On the other hand, it is displayed by specifying an empty character string.
        //Erase the tag

        //Of course, when this process is called for the first time, there is nothing, so an empty string is fine.
        //When called for the second time, search-result is empty
        tagName.forEach((tag) => {
          const childElement = document.createElement("div");
          childElement.setAttribute("class", "child");
          childElement.setAttribute("id", tag.id);
          childElement.innerHTML = tag.name;
          searchResult.appendChild(childElement);
          const clickElement = document.getElementById(tag.id);
          clickElement.addEventListener("click", () => {
            document.getElementById("tweets_tag_name").value = clickElement.textContent;
            clickElement.remove();
          });
        });
      };
    });
  });
};
Eliminate the error when you do not fill in the form

Incremental search is supposed to work when something is entered in the form. However, the keyup specified for this event will also fire even with a "key that does not enter characters even if pressed" such as the backspace key.

As a result, since there is no string to use for the search, there is no data in the response, and an error occurs because we are trying to define a non-existent one in tagName. Let's process to display the tag only when there is data in the response.

If you try to define tagName even if there is no data in the response, an error will occur because XHR.response is null. Let's modify so that the tag is displayed only when there is data in the response. Use the if statement to solve the problem as shown below.

tag.js


if (location.pathname.match("tweets/new")){
  document.addEventListener("DOMContentLoaded", () => {
#abridgement
      XHR.send();
      XHR.onload = () => {
        const searchResult = document.getElementById("search-result");
        searchResult.innerHTML = "";
        if (XHR.response) {
          //The keyup specified for the event is the backspace key
          //Even if you press a key such as, no characters are entered, it will ignite.

          //An error occurs if you define a non-existent one in tagName

          //Let's process to display the tag only when there is data in the response

         
          const tagName = XHR.response.keyword;
          tagName.forEach((tag) => {
            const childElement = document.createElement("div");
            childElement.setAttribute("class", "child");
            childElement.setAttribute("id", tag.id);
            childElement.innerHTML = tag.name;
            searchResult.appendChild(childElement);
            const clickElement = document.getElementById(tag.id);
            clickElement.addEventListener("click", () => {
              document.getElementById("tweets_tag_name").value = clickElement.textContent;
              clickElement.remove();
            });
          });
        };
      };
    });
  });
};

This completes the implementation. Thank you for your hard work.

Summary of tag.js code
if (location.pathname.match("drinks/new")){
  // location.pathname is
  //Get or change the path of the URL of the current page
  // .match returns the matching result of the string passed as an argument

  //Currently drinks/Event fire when in new
  document.addEventListener("DOMContentLoaded",()=>{
    //addEventListener executes various event processing
    //Methods that can be

    //document is the whole html element

    // DOMContentLoaded"Is
    //Activated when the web page load is completed

    //The range of event firing is wide ...?
    const inputElement = document.getElementById("tweet_tag_name")

    inputElement.addEventListener("keyup",()=>{
      //When you fill out the form and the keyboard is released
      //Event will be fired in sequence

      const keyword = document.getElementById("tweet_tag_name").value;
      //Get the value entered in the text box
      const XHR = new XMLHttpRequest();
      //XHLHttpRequest is an object to enable Ajax on the server
      //HTTP requests can be made asynchronously
    
      //Create an instance and assign it to a variable
      XHR.open("GET",`search/?keyword=${keyword}`,true);
      //open specifies the type of request
      //First argument HTTP method specification
      //Specifying the second argument path
      //Third argument Asynchronous communication ON/OFF

      //With a GET request
      // ?You can pass parameters with
      // ?keyword is a key${keyword}Is the value

      //The query parameter is http://sample.jp/?name=Like tanaka
      //A URL parameter that spells information after the "?".
      //The structure after "?"?<Variable name>=<value>It has become.
      // ?Used when you want to search for character strings

      //I want to move the search action
      //The reason why drinks is omitted
      //Based on the directory one level above the specified path
      //You can specify a relative path



      //For the time being, drinks#Send a request to search
      //I want to predictively convert

      XHR.responseType = "json";
      //The format of the data returned from the controller
      //Good compatibility with js and easy to handle as data
      //json format is specified
      XHR.send();
      // tag.I want to send from js to the server side
      //Now that we have defined the request
      //Let's describe the process to send
      XHR.onload = () => {


        const searchResult = document.getElementById("search-result");
        // 1.The place to display the tag,search-get result
        searchResult.innerHTML = "";
        //The same tag stays displayed many times
        //I want to delete the previous search result

        //In the innerHTML property of the element inserting the search result
        //On the other hand, it is displayed by specifying an empty character string.
        //Erase the tag

        //Of course, when this process is called for the first time, there is nothing, so an empty string is fine.
        //When called for the second time, search-result is empty
        if (XHR.response){
          //The keyup specified for the event is the backspace key
          //Even if you press a key such as, no characters are entered, it will ignite.

          //An error occurs if you define a non-existent one in tagName

          //Let's process to display the tag only when there is data in the response

          const tagName = XHR.response.keyword;
          //When server-side processing is successful
          //The data returned as a response
          //Receive,Assign to variable
  
          //To receive data
          //Use the response property

          tagName.forEach((tag) => {
          //The reason for using forEach is the rails search action
          //So, I will put out multiple tags that got caught in the search
          //Because in some cases
          const childElement = document.createElement("div");
          // 2.Creating an element to display the tag
          //As the name suggests,Method to create element
         

          childElement.setAttribute("class", "child");
          childElement.setAttribute("id", tag.id);
          //Class in the created div tag,Give id
          //I'm using the tag of a local variable created by forEach here

          childElement.innerHTML = tag.tag_name;
          // <div>tagname</div>Feeling
          //With innerHTML,
          //Replace, rewrite, or insert the contents
          // 3.The tag of the tag returned from the server side_name
          //Image to put in childElement
           searchResult.appendChild(childElement);
          //html search-As a child element of result
          //childElements line up

          //I will display it for the first time here
          
          const clickElement = document.getElementById(tag.id);
          //I want the clicked tag name to be entered in the form

          //Once you enter,id = tag.html element of id div
          //Should be done, so get it
          clickElement.addEventListener("click",()=>{
            //event fires when the clickElement element is clicked
            document.getElementById("tweet_tag_name").value = clickElement.textContent;
            // form_Get the element of id made with with
            //further.By setting it to value, it was actually entered
            //Get value

            //clickElement has the name of the tag, so
            // .You can get the name of the tag with textContent

            //Now when you click on the tag part, the name of the tag will be
            //Enter the form
            clickElement.remove();
            //Only the clicked tag disappears
          });
          });
        };
      };
    });
  });
};

Recommended Posts

Try to implement tagging function using rails and js
[Rails] I tried to implement "Like function" using rails and js
Rails learning How to implement search function using ActiveModel
Try to implement iOS14 Widget function
[Java] Try to implement using generics
Try to implement login function with Spring-Boot
How to implement image posting using rails
Implement star rating function using Raty in Rails6
Flow to implement image posting function using ActiveStorage
[Rails] Implement search function
Rails API mode I tried to implement the keyword multiple search function using arrays and iterative processing.
How to implement image posting function using Active Storage in Ruby on Rails
Continued ・ Flow to implement image posting function using ActiveStorage
[Rails, JS] How to implement asynchronous display of comments
Try to implement using Rakuten product search API (easy)
[Rails] Create sitemap using sitemap_generator and deploy to GAE
Implement a reservation system using Rails and simple calendar! Let's add validation to datetime!
[Ruby on Rails] How to implement tagging / incremental search function for posts (without gem)
How to implement a circular profile image in Rails using CarrierWave and R Magick
Implement application function in Rails
[Rails] Implement User search function
Search function using [rails] ransack
Try using view_component with rails
Implement follow function in Rails
Ajax bookmark function using Rails
[Rails] How to implement scraping
[Rails] Try using Faraday middleware
[Rails] Implement image posting function
Implement Thread in Java and try using anonymous class, lambda
Implement login function in Rails simply by name and password (1)
Implement login function in Rails simply by name and password (2)
[Rails] Implementation of tagging function using intermediate table (without Gem)
[Rails] Function to search and list products from multi-level categories
[Rails] Implement event end function (logical deletion) using paranoia (gem)
How to set and describe environment variables using Rails zsh
Implement login function simply with name and password in Rails (3)
Implement user registration function and corporate registration function separately in Rails devise
[Rails] Implement community membership application / approval function using many-to-many associations
[Rails] A simple way to implement a self-introduction function in your profile
I tried to implement Ajax processing of like function in Rails
Try to implement Yubaba in Ruby
[Rails] Tag management function (using acts-as-taggable-on)
[Swift] How to implement the Twitter login function using Firebase UI ①
I tried to implement the image preview function with Rails / jQuery
Implement simple login function in Rails
Implement tagging function in form object
[Rails] [jQuery] Asynchronous like function implementation using remote: true and js.erb
[Rails] How to upload images to AWS S3 using Carrierwave and fog-aws
[Rails] How to implement star rating
[Rails] How to upload images to AWS S3 using refile and refile-s3
Try to implement Yubaba in Java
Implement CSV download function in Rails
A story about using the CoreImage framework to erase stains with Swift and implement a blur erase function
[Swift] How to implement the Twitter login function using Firebase UI ②
[Rails] Reflection to db using seeds.rb
How to implement a slideshow using slick in Rails (one by one & multiple by one)
[Rails] Create an evaluation function using raty.js
How to implement search functionality in Rails
Install Webpacker and Yarn to run Rails
[Rails] How to upload images using Carrierwave
Try to implement n-ary addition in Java