所以我对我涉及Javascript的问题有了更好的理解。问题在于,在AJAX调用刷新div的内容之后,该div中的内容被取消链接或未初始化为Javascript。我想要做的是让我的活动列表可以为用户排序。我使用优先级字段来保存活动的顺序,因此当用户刷新或离开页面时,则维护订单。
我收到的问题如下:
ActiveRecord :: RecordNotFound(无法找到带有' id' =项目的活动):
因此,不会保存活动订单。这发生在AJAX调用和刷新之后,并且它事先正常工作,保存顺序等等。我已经尝试了一些解决方案,例如one并将Javascript移到部分无法成功。
我认为上面的错误是活动没有正确链接到Javascript文件的结果,导致它的ID为" item"那么有谁知道如何解决这个问题或任何有关如何解决它的建议?谢谢!
主要观点:
<!-- home.html.erb -->
<!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">
<title>Bootstrap 101 Template</title>
</head>
<!-- the jScrollPane script -->
<!--IF THE USER IS LOGGED IN, DISPLAY THE FOLLOWING -->
<% if current_user %>
<!--
<style>
.navbar {
background-color:#2F4F4F
}
</style>
-->
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<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='home'>TimeTracker</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Signed in as <%=current_user.email %></a></li>
<li>
<%= link_to 'Sign Out', sign_out_path, method: :delete %>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<h1 align = "center">Activities</h1>
<div id = 'activity_container'>
<ul id="Categories" class="connectedSortable">
<% @categories.each do |cats| %>
<% if cats.user_id == current_user.id%>
<div class="panel-group">
<div class="panel text-left">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse<%= cats.id%>">
<%= cats.c_name %>
</a>
</h4>
</div>
<div id="collapse<%= cats.id%>" class="panel-collapse collapse">
<ul id="category_activities" class=".connectedSortable">
<% cats.activities.each do |activity| %>
<li class="list-group-item" >
<% if activity.hidden == false || activity.hidden == nil%>
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<!--<button class="editActivity" style="border:none; padding:0; background-color: transparent">-->
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
<!--</button>-->
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
<% end %>
<% end %>
</li>
</ul>
</div>
</div>
</div>
<% end %>
<% end %>
</ul>
<ul id="Activities" class="connectedSortable" >
<!-- List each activity in database -->
<% @activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id='<%=activity.id%>' style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
</ul>
</div>
<ul class="pager">
<li class="previous"><a href="#"><span aria-hidden="true">←</span>Previous </a></li>
<li class="next"><a href="#"> Next<span aria-hidden="true">→</span></a></li>
<!-- *****************NEW*********************** -->
<%= form_for @activity, :url => create_act_path, remote: true, data: {type: 'script'} do |a| %>
<%= a.text_field :a_name, id: 'a_name_field', placeholder: 'Activity Name'%>
<%= a.select :category_id, Category.all.collect { |c| [c.c_name, c.id] }, include_blank: "--No Category--" %>
<%= a.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<%= form_for @category, :url => create_cat_path, remote: true do |c| %>
<%= c.text_field :c_name, id: 'c_name_field', placeholder: 'Category Name'%>
<%= c.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<!-- Button for showing all hidden items -->
<%= link_to unhide_act_path, method: :post do %>
<button class="showHidden" >Show Hidden</button>
<% end %>
<!-- Button to sort -->
<button class="sortActivity">Sort</button>
<button class="doneSorting">Done Sorting</button>
<!-- ***************************************** -->
</ul>
<!-- IF THE USER IS NOT LOGGED IN, DISPLAY THE FOLLOWING -->
<% else %>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">TimeTracker</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="active">
</li>
</ul>
</div>
</div>
</nav>
<div class="loginContainer" align="center">
<h1 align="center">
<b>
Please log in or sign up
</b>
</h1>
<div class="container">
<br>
<%= button_to 'Login', sign_in_path, :method => 'get', class: 'btn' %>
<br>
<%= button_to 'Sign Up', sign_up_path, :method => 'get', class: 'btn' %>
</div>
<!--<div class="container" style="background-color:#D3D3D3">
<input type="checkbox" checked="checked"> Remember me
<span class="psw">Forgot <a align="center" href="#">password?</a></span>
</div> -->
</div>
<% end %>
<script type="text/javascript">
function changeImg(img) {
if (img.src == "<%=asset_path('_unfilledbubble.png')%>"){
img.src = "<%=asset_path('_filledbubble.png')%>";
}
else {
img.src = "<%=asset_path('_unfilledbubble.png')%>";
}
}
</script>
<script type="text/javascript">
$(document).ready(function() {
$(function () {
$('.scroll-pane').jScrollPane({showArrows: true});
});
});
</script>
<script>
$(document).ready(function(){
function callAll(){
set_positions = function(){
// loop through and give each task a data-pos
// attribute that holds its position in the DOM
$('.list-group-item').each(function(i){
$(this).attr("data-pos",i+1);
});
}
// ready = function(){
// call set_positions function
set_positions();
// ************NEW execept for #Activities
$('#Activities').sortable({
connectWith: ".connectedSortable"
});
$('#Activities').disableSelection();
// $('#Categories').sortable({
// connectWith: ".connectedSortable"
// });
// $('#Categories').disableSelection();
$('#category_activities').sortable({
connectWith: ".connectedSortable"
});
$('#category_activities').disableSelection();
// *******end of NEW
$('#Activities li').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
// after the order changes
$('#Activities').sortable().bind('sortupdate', function(e, ui) {
// array to store new order
var updated_order = []
// set the updated positions
set_positions();
// populate the updated_order array with the new task positions
$('#Activities li').each(function(i){
updated_order.push({ id: $(this).attr('id'), position: i });
});
// send the updated order via ajax
$.ajax({
type: "PUT",
url: '/home/sort',
data: { order: updated_order }
});
});
}
$(document).ajaxComplete(callAll());
})
</script>
部分视图:
<!-- List each activity in database -->
<% @activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id="item" data-id="<%activity.id%>" style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to activity, method: :post, :controller => :activities, :action => :set_hidden_true, remote: true do %>
<button class="hideActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
</button>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
创建活动JS文件:
<!--create_activity.js.erb-->
$('#Activities').html("<%= j (render 'object') %>");
家庭控制器:
class HomeController < ApplicationController
respond_to :html, :js
def new
end
def index
end
def home
@activities = Activity.all
@activity = Activity.new
@categories = Category.all
@category = Category.new
end
def create_activity
@activity = Activity.create(activity_params)
@activity.user_id = current_user.id
@activity.priority = @activity.id
@object = Category.all
@activities = Activity.all
@categories = Category.all
if @activity.save
flash[:success] = 'Activity created successfully'
else
flash[:notice] ='ERROR: Activity could not be create'
end
end
def create_category
@category = Category.new(category_params)
@category.user_id = current_user.id
#@category.priority = @category.id
@object = Category.all
@activities = Activity.all
@categories = Category.all
#@category.priority = @category.id
if @category.save!
flash[:success] = 'Category created successfully!'
else
flash[:error] = 'ERROR: Category was not saved!'
end
end
def destroy_activity
@activity = Activity.find(params[:id])
@activity.destroy
@object = Category.all
@activities = Activity.all
@categories = Category.all
end
def welcome
end
def hide_activity
@object = Category.all
@activities = Activity.all
@categories = Category.all
@activity = Activity.find(params[:id])
@activity.update_attribute(:hidden, true)
respond_to do |format|
format.html {redirect_to activities_url}
format.js
end
end
#NEW 4/15
def edit_activity
@activity = Activity.find(params[:id])
end
def update_activity
@activity = Activity.find(params[:id])
if @activity.update_attributes(activity_params)
flash[:success] = 'Activity updated successfully!'
else
flash[:notice] = 'Activity was not updated'
end
end
def unhide_all
@object = Category.all
@activities = Activity.all
@categories = Category.all
@activities = Activity.all
@activities.update_all(hidden: false)
# redirect_to root_path
end
def sort
params[:order].each do |key, value|
Activity.find(value[:id]).update_attribute(:priority, value[:position])
end
render :nothing => true
end
private
def activity_params
params.require(:activity).permit(:a_name, :category_id)
end
def category_params
params.require(:category).permit(:c_name)
end
end
更新
我尝试了following并作为测试,用以下内容替换了html中的脚本:
$('#Activities').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
在Ajax之前,当我点击一个活动时,它正确地给了我它的id。但是,在进行Ajax调用之后,当我尝试点击某个活动时,我得到了相同的错误,声称它无法找到一个活动&#34; id = item&#34;
答案 0 :(得分:0)
这里有很多选项,一个选项是将绑定更改为文档或正文,而不是直接更改为元素的id,因为这是以dinamically方式创建的,例如:
$("body").on('click',"#Activities" ,function () {
var myid = $(this).attr('id');
alert(myid);
});
您可以在呈现不推荐的元素时再次初始化ajax请求上的事件
或使用像https://github.com/adampietrasiak/jquery.initialize这样的插件,如果将它绑定到类,ID或其他选择器,可以重新插入插件。
答案 1 :(得分:0)
我已经创建了一个示例,您可以使用AJAX请求从索引页面创建Person
。创建Person
后,将people
的新列表发送到索引页面。为了模拟你的JavaScript,我使用jQuery将每个元素的背景颜色设置为蓝色。
让我们从index.html.erb
本身开始。
<!-- app/views/people/index.html.erb -->
<p id="notice"><%= notice %></p>
<h1>People</h1>
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody id="people_tbody">
<%= render 'people', people: @people %>
</tbody>
</table>
<%= render('form', person: @people.new) %>
接下来是两个部分_people.html.erb
:
<!-- app/views/people/_people.html.erb -->
<% people.each do |person| %>
<tr>
<td><%= person.first_name %></td>
<td><%= person.last_name %></td>
<td><%= link_to 'Show', person %></td>
<td><%= link_to 'Edit', edit_person_path(person) %></td>
<td><%= link_to 'Destroy', person, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
和_form.html.erb
从中解雇AJAX请求:
<!-- app/views/people/_form.html.erb -->
<%= form_for(person, remote: true) do |f| %> <!-- remote true, makes it an AJAX call -->
<% if person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% person.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</div>
<div class="actions">
<%= f.submit %> <!-- when submit is clicked the AJAX request is fired to PeopleController#create -->
</div>
<% end %>
要模拟您的JavaScript问题,我有以下文件:
// app/assets/javascripts/people.js
function init_people() {
$('#people_tbody tr').css('background-color', 'lightblue')
}
$(document).ready(init_people)
这为所有行提供浅蓝色背景。
正如您所看到的,我使用AJAX发送填写的表单,因为设置了remote: true
。如果表单已提交,请求将以PeopleController#create
的形式到达,如下所示:
# app/controllers/people_controller.rb
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
@people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
@person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create # AJAX request arrives here
@person = Person.new(person_params)
respond_to do |format|
if @person.save
format.html { redirect_to @person, notice: 'Person was successfully created.' }
format.json { render :show, status: :created, location: @person }
# I added the underlying line to handle the AJAX response.
format.js { render :index, status: :created, location: @person }
else
format.html { render :new }
format.json { render json: @person.errors, status: :unprocessable_entity }
# I added the underlying line to handle the AJAX response.
format.js { render nothing: true }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if @person.update(person_params)
format.html { redirect_to @person, notice: 'Person was successfully updated.' }
format.json { render :show, status: :ok, location: @person }
else
format.html { render :edit }
format.json { render json: @person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
@person.destroy
respond_to do |format|
format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
@person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:first_name, :last_name)
end
end
正如您所看到的,我添加了两行来处理js
中的PeopleController#create
格式。如果渲染来自format.js { ... }
rails知道选择index.js.erb
文件,而不是index.html.erb
文件。如果您不想要此行为,则可以指定特定文件。
我的index.js.erb
看起来像这样:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
这会将#people_tbody
的内容替换为新设置的op人(与您的示例类似)。但现在我遇到了和你一样的问题。 JavaScript不再被触发,每行的背景都是白色的。要在新加载的内容上触发JavaScript,我只需要调用init函数。 这意味着在文档准备好之后以及应该将AJAX请求提取到单独的函数之后要应用的任何逻辑。我将我的逻辑放在函数init_people()
中。
这意味着index.js.erb
应如下所示:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
init_people()
现在,在加载AJAX内容之后,触发init_people()
函数为新加载的内容设置JavaScript。