在 Ajax 请求后根据模型中的值更新 CSS class
Update CSS class based on value in model after Ajax request
我有一个显示剧集列表的视图。我为此使用了一部分:
<div class="episode-list">
<% if user_signed_in? %>
<%= render partial: "shared_partials/episode_with_image_compact", collection: @recent_episodes, as: :episode %>
<% end %>
</div>
在该部分中,我有一个 button_to 向后端发送请求以将剧集标记为已看到:
<%= button_to manual_new_scrobble_path, {method: :post, form_class: 'manual-scrobble-btn', class: "button is-small #{'listened' if episode.has_play}", remote: true, params: {scrobble: {user_id: current_user.id, episode_id: episode.id}}} do %>
<%= scrobble_icon(episode) %>
<% end %>
scrobble_icon
函数只是根据剧集的状态设置 class,如下所示:
def scrobble_icon(episode)
if episode.has_play
icon('fas', 'check', class: 'listened')
else
icon('fas', 'check', class: 'unlistened')
end
end
我正在使用 remote: true
,因此它不会导致页面加载。当我为 SPA 做其他前端框架时,默认情况下总是有这种双向绑定,其中值会根据 "store" / 模型的状态更新。
我现在已经阅读了多篇关于 TurboLinks and server generated javascript 的文章,但我仍然无法找出解决问题的正确方法。
我想要的:
- 点击按钮
- 请求成功并向数据库写入值
- 按钮现在有 class "listened"
实际发生了什么:
- 点击按钮
- 请求成功并向数据库写入值
- 按钮看起来一样
- 我重新加载页面,按钮现在有 class "listened"
很多类似问题的回答都讲到jQuery也就是:
1) 不再是 Rails 6
2) 不是我想在 2019 年使用的东西
谢谢!
您需要呈现一个 javascript 脚本:
1 - 找到元素
2 - 更新为 class
首先我会添加一些标识符,以便您可以识别正确的按钮
<%= button_to manual_new_scrobble_path, {method: :post, form_class: 'manual-scrobble-btn', class: "button is-small #{'listened' if episode.has_play}", id: "button_for_episode_#{episode.id}", remote: true, params: {scrobble: {user_id: current_user.id, episode_id: episode.id}}} do %>
<%= scrobble_icon(episode) %>
<% end %>
注意 `id: "button_for_episode_#{episode.id}" 参数
现在您可以使用类似这样的内容来定位它:
// find the button
let button = document.getElementById("button_for_episode_#{params[:scobble][:episode_id]}");
// add the class
button.classList.add('listened');
// find the icon within that button
let icon = button.querySelector('.fas');
// remove "unlistened" class
icon.classList.remove('unlistened');
// add "listened" class
icon.classList.add('listened');
此脚本应该是您正在调用的操作的视图。
最后我要做的是添加 class,如 arieljuod 的回答中所述,但我在之前的回复中不理解的构建块如下。
在您的 app/javascript/packs/application.js
(如果您愿意,也可以自定义)中,您必须在 ajax:success
事件上设置一个侦听器,该事件由 Rails 发出,如 documentation。
然后我们必须在事件中检查我们唯一的 id
以区分来自其他来源的事件。然后我们添加/删除 classes,一切都按预期工作。
到目前为止它似乎工作正常,如果我遗漏了什么请告诉我!
document.addEventListener('ajax:success', function (event) {
let detail = event.detail;
let data = detail[0], status = detail[1], xhr = detail[2];
// Check if our event is from an manual episode scrobble button
let button = [...event.target.children].find(element => element.id === 'scrobble_btn_episode' + data.episode_id);
// If find() is not successful it's undefined
if (typeof button !== 'undefined') {
// We set the classes on our button
button.classList.add("listened");
button.classList.remove("unlistened");
// The button has a child, we also set the classes there for the check mark
let id = button.getElementsByClassName('fa-check');
id[0].classList.add("listened");
id[0].classList.remove("unlistened");
}
});
我有一个显示剧集列表的视图。我为此使用了一部分:
<div class="episode-list">
<% if user_signed_in? %>
<%= render partial: "shared_partials/episode_with_image_compact", collection: @recent_episodes, as: :episode %>
<% end %>
</div>
在该部分中,我有一个 button_to 向后端发送请求以将剧集标记为已看到:
<%= button_to manual_new_scrobble_path, {method: :post, form_class: 'manual-scrobble-btn', class: "button is-small #{'listened' if episode.has_play}", remote: true, params: {scrobble: {user_id: current_user.id, episode_id: episode.id}}} do %>
<%= scrobble_icon(episode) %>
<% end %>
scrobble_icon
函数只是根据剧集的状态设置 class,如下所示:
def scrobble_icon(episode)
if episode.has_play
icon('fas', 'check', class: 'listened')
else
icon('fas', 'check', class: 'unlistened')
end
end
我正在使用 remote: true
,因此它不会导致页面加载。当我为 SPA 做其他前端框架时,默认情况下总是有这种双向绑定,其中值会根据 "store" / 模型的状态更新。
我现在已经阅读了多篇关于 TurboLinks and server generated javascript 的文章,但我仍然无法找出解决问题的正确方法。
我想要的:
- 点击按钮
- 请求成功并向数据库写入值
- 按钮现在有 class "listened"
实际发生了什么:
- 点击按钮
- 请求成功并向数据库写入值
- 按钮看起来一样
- 我重新加载页面,按钮现在有 class "listened"
很多类似问题的回答都讲到jQuery也就是:
1) 不再是 Rails 6
2) 不是我想在 2019 年使用的东西
谢谢!
您需要呈现一个 javascript 脚本: 1 - 找到元素 2 - 更新为 class
首先我会添加一些标识符,以便您可以识别正确的按钮
<%= button_to manual_new_scrobble_path, {method: :post, form_class: 'manual-scrobble-btn', class: "button is-small #{'listened' if episode.has_play}", id: "button_for_episode_#{episode.id}", remote: true, params: {scrobble: {user_id: current_user.id, episode_id: episode.id}}} do %>
<%= scrobble_icon(episode) %>
<% end %>
注意 `id: "button_for_episode_#{episode.id}" 参数
现在您可以使用类似这样的内容来定位它:
// find the button
let button = document.getElementById("button_for_episode_#{params[:scobble][:episode_id]}");
// add the class
button.classList.add('listened');
// find the icon within that button
let icon = button.querySelector('.fas');
// remove "unlistened" class
icon.classList.remove('unlistened');
// add "listened" class
icon.classList.add('listened');
此脚本应该是您正在调用的操作的视图。
最后我要做的是添加 class,如 arieljuod 的回答中所述,但我在之前的回复中不理解的构建块如下。
在您的 app/javascript/packs/application.js
(如果您愿意,也可以自定义)中,您必须在 ajax:success
事件上设置一个侦听器,该事件由 Rails 发出,如 documentation。
然后我们必须在事件中检查我们唯一的 id
以区分来自其他来源的事件。然后我们添加/删除 classes,一切都按预期工作。
到目前为止它似乎工作正常,如果我遗漏了什么请告诉我!
document.addEventListener('ajax:success', function (event) {
let detail = event.detail;
let data = detail[0], status = detail[1], xhr = detail[2];
// Check if our event is from an manual episode scrobble button
let button = [...event.target.children].find(element => element.id === 'scrobble_btn_episode' + data.episode_id);
// If find() is not successful it's undefined
if (typeof button !== 'undefined') {
// We set the classes on our button
button.classList.add("listened");
button.classList.remove("unlistened");
// The button has a child, we also set the classes there for the check mark
let id = button.getElementsByClassName('fa-check');
id[0].classList.add("listened");
id[0].classList.remove("unlistened");
}
});