简体   繁体   中英

How to use Javascript and AJAX to render popup on index page Ruby on Rails 5

I have a simple inventory system application I've been developing for a class project. One of the requirements is to have some form of Javascript and AJAX doing something in the app. It doesn't have to be anything large or super complicated, but it does have to be there. What my group decided to do was render a popup that displays information about an item when you click on the 'show' link, as it was similar to an example the professor did in class and it was somewhat useful for our app as well. However I cannot get it to work, it just bypasses the ajax and javascript stuff and goes straight to the show.html.haml page. Here is my code:

index.html.haml

%p#notice= notice
%h1 Items
%table
  %thead
    %tr
      %th Name
      %th Description
      %th Quality
      %th Price
      %th Location
      %th Options
  %tbody
    - @items.each do |item|
      %tr
        %td= item.name
        %td= item.description
        %td
          = item.quality
          %br/
          %br/
          = item.quality_desc
        %td= item.price
        %td= item.location
        %td{:colspan => "3"}
          = link_to 'Show', item, class: "items" 
          = link_to 'Edit', edit_item_path(item)
          = link_to 'Destroy', item, method: :delete, data: { confirm: 'Are you sure?' }
%br/
= link_to 'New Item', new_item_path

_item.html.haml

This is the information that the popup is supposed to display

%h1 Items
%h2
  = item.name
  , #{item.category}
%br/
- item.images.each do |image|
  = image_tag(image.small.url)
%br
Price: $#{item.price}
%br/
Description: #{item.description}
%br/
Quality: #{item.quality},
\#{item.quality_desc}
%br/
Location: #{item.location}
%br/
%br/
%br/
= link_to 'Edit', edit_item_path(@item)
= link_to 'Close', '', id: 'closeLink'

items_controller.rb

class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :edit, :update, :destroy]

  # GET /items
  # GET /items.json
  def index
    @items = Item.all
  end

  # GET /items/1
  # GET /items/1.json
  def show
    render(:partial => 'item', :object => @item) if request.xhr?
  end

  # GET /items/new
  def new
    @item = Item.new
  end

  # GET /items/1/edit
  def edit
  end

  # POST /items
  # POST /items.json
  def create
    @item = Item.new(item_params)

    respond_to do |format|
      if @item.save
        format.html { redirect_to @item, notice: 'Item was successfully created.' }
        format.json { render :show, status: :created, location: @item }
      else
        format.html { render :new }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /items/1
  # PATCH/PUT /items/1.json
  def update
    respond_to do |format|
      if @item.update(item_params)
        format.html { redirect_to @item, notice: 'Item was successfully updated.' }
        format.json { render :show, status: :ok, location: @item }
      else
        format.html { render :edit }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /items/1
  # DELETE /items/1.json
  def destroy
    @item.destroy
    respond_to do |format|
      format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_item
      @item = Item.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def item_params
      params.fetch(:item, {}).permit(:name, :description, :quality, :quality_desc, :price, :location, :category, { images: [] })
    end
end

items.js

var ItemPopup = {
    setup: function() {
        // add hidden 'div' to end of page to display popup:
        var popupDiv = $('<div id="itemInfo"></div>');
        popupDiv.hide().appendTo($('body'));
        $(document).on('click', '#items a', ItemPopup.getItemInfo);
    },
    getItemInfo: function() {
        $.ajax({type: 'GET',
            url: $(this).attr('href'),
            timeout: 5000,
            success: ItemPopup.showItemInfo,
            error: function(xhrObj, textStatus, exception) {alert('Error!'); }
            //'success' and 'error' functions will be passed 3 args
        });
        return(false);
    },
    showItemInfo: function(data, requestStatus, xhrObject) {
        //center a floater 1/2 as wide and 1/4 as tall as screen
        var oneFourth = Math.ceil($(window).width() / 4);
        $('#itemInfo').css({'left': oneFourth, 'width': 2*oneFourth, 'top': 250}).html(data).show();
        //make the Close link in the hidden element work
        $('#closeLink').click(ItemPopup.hideItemInfo);
        return(false); //prevent default link action
    },
    hideItemInfo: function() {
        $('#itemInfo').hide();
        return(false);
    }
};
$(ItemPopup.setup);

application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
// require turbolinks
// require_tree .
//= require items

application.html.haml

!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title InventoryManager
    = csrf_meta_tags
    // = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    // = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
    = stylesheet_link_tag 'application'
    = javascript_include_tag "application"
  %body
    %nav.navbar.navbar-default
      .container-fluid
        / Brand and toggle get grouped for better mobile display
        .navbar-header
          %button.navbar-toggle.collapsed{"aria-expanded" => "false", "data-target" => "#bs-example-navbar-collapse-1", "data-toggle" => "collapse", :type => "button"}
            %span.sr-only Toggle navigation
            %span.icon-bar
            %span.icon-bar
            %span.icon-bar
          %a.navbar-brand{:href => "/default/index"} InventoryManager
        / Collect the nav links, forms, and other content for toggling
        #bs-example-navbar-collapse-1.collapse.navbar-collapse
          %ul.nav.navbar-nav
            %li.active
              %a{:href => "#"}
                Items
                %span.sr-only (current)
          %ul.nav.navbar-nav.navbar-right
            - if admin_signed_in?
              %li= link_to "Logout", destroy_admin_session_path, :method => :delete
            - elsif employee_signed_in?
              %li= link_to "Logout", destroy_employee_session_path, :method => :delete
            - else
              %li
                %a{:href => "/admins/sign_in"} Admin
              %li
                %a{:href => "/employees/sign_in"} Staff
        / /.navbar-collapse
      / /.container-fluid
    = yield

If you need anymore of the code just ask. This is in Ruby on Rails 5

EDIT: So I fixed it by changing the selector in the event handler function so that it read '#items' and it grabbed the elements on my page with that id. However I got the code I was trying to use originally from a textbook, implying that what was there was supposed to work. Can someone explain to me why it didn't work initially?

EDIT2: Nevermind I figured it out.

So it turns out my trouble was this line right here:

$(document).on('click', '#items a', ItemPopup.getItemInfo);

I got this code from my class's textbook and modified it slightly to fit my application. As a result of this and a lack of knowledge of how the selectors worked, I thought this was selecting anchor tags with an id of 'items'. As it turns out, what it was actually doing is getting all the anchor tags inside an element with an id of 'items', in the case of the book, this particular element was a table, and the only links inside that table went to that applications show.html.haml page. That didn't quite work for my app since the index table has 3 different types of links on it, so I changed the line to read

$(document).on('click', '.items', ItemPopup.getItemInfo);

and changed the 'show' links on my index.html.haml to have a class of 'items'. This fixed my problem and it works perfectly now.

That being said if there is a solution to this sort of problem that is considered a better practice feel free to share it as an answer to this proble, as well, I'm all for learning something new.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM