Understanding Django/REST/JS code functionality - javascript

I have the following code in my website:
<tr onclick="editUsers(29)" data-id="29">
editUsers:
function editUsers(id) {
loadUsers(false, id, showUsers, true);
}
loadUsers:
function loadUsers(insert, id, func_call, html_form) {
var data = insert ? {insert: true} : {}
if (html_form)
data.html_form = true;
$.ajax({
type: 'GET',
url: '/rest/user/' + id + '/',
data: data
})
.done(function (data) {
func_call(data, insert, id);
})
.fail(function () {
});
}
When I click on the row, it should open an interface to edit the selected row/user, but nothing happens. I do get a reply in the console, which looks like it should work, but it doesn't. Can someone explain why it doesn't work?
The reply in question:"GET /rest/user/29/?html_form=true HTTP/1.1" 200 3170
I have the same functionality elsewhere in my code, which adds a new user:
function addUsers() {
loadUsers(true, 0, showUsers, true);
}
<div class="btn btn-primary pull-right" onclick="addUsers()">Add User</div>
The above doesn't work, editing the user doesn't either.
EDIT: showUsers function
function showUsers(data, insert, id) {
var form = $(data),
$a= form.find('select[name="a"]'),
$b= form.find('select[name="b"]');
$a.on("change", function (e) { $b.val($a.val()).trigger('change'); });
var p = {
type: BootstrapDialog.TYPE_PRIMARY,
title: '{% trans "Add User" %}',
message: form,
closable: true,
cssClass: 'usersDialog',
buttons: [
{
label: gettext('Cancel'),
hotkey: 27,
action: function (dlg) { dlg.close(); }
},
{
label: gettext('Save'),
cssClass: 'btn-primary',
action: function (dlg) {
var data = form.find('#users-form').serializeForm();
dlg.close();
var storeData = function storeData(data) {
data.html_form = true;
$.ajax({
type: data.id == '' ? 'POST' : 'PUT',
url: '/rest/user/' + (data.id == '' ? '' : data.id + '/'),
data: data,
dataType: 'json',
headers: {'X-CSRFToken': '{{ csrf_token }}'}
})
.done(function (res) {
//self.updDeviceFields(res);
if (conflictDialogs.length > 0)
storeData(conflictDialogs.pop());
else
location.reload();
//$.dreamAlert({type: 'success', message: gettext('Changes saved'), position: 'right'});
}).fail(function (jqXHR, textStatus, errorThrown) {
console.log([jqXHR.status, jqXHR, textStatus, errorThrown]);
if (jqXHR.status == 400) {
p.message = $(jqXHR.responseText);
form = p.message;
currentForm = form;
currentDialog = BootstrapDialog.show(p);
}
else if (jqXHR.status == 500) {
currentDialog = BootstrapDialog.show(p);
}
//$.dreamAlert({type: 'error', message: gettext('Error saving changes'), position: 'right'});
});
}
storeData(data);
}
}
]
}
if (conflictDialogs.length > 0) {
p.animate = false;
p.cssClass += ' flip';
}
currentDialog = BootstrapDialog.show(p);
currentForm = form;
}

I figured this out when I dug deep into the code. Turns out I had a syntax error which I completely missed when writting the code.
When copy pasting the code from a different page, I copied the variable name as well. My HTML looked like this:
<div class="row">
<div class="col-xs-6">{% render_field foo_form.one bar_style %}</div>
<div class="col-xs-6">{% render_field foo_form.two bar_style %}</div>
</div>
When it should have looked like this:
<div class="row">
<div class="col-xs-6">{% render_field foo_form.one foo_style %}</div>
<div class="col-xs-6">{% render_field foo_form.two foo_style %}</div>
</div>
I didn't see the style of importance, since it was defined as an empty list, so I completely missed the error.

Related

How to add Antiforgery protection to such asp.net-mvc application?

I have an old asp.net mvc project using JS. I need to add Cross-Site Request Forgery protection, but I don't know, how to implement it in my case.
Could somebody help me with this, please?
chtml-view:
#model WebGridResults<IndexingCollectionModel>
#{
ViewBag.Title = "Manage Collections";
Layout = "~/_Indexing.cshtml";
}
#section grid_options
{
<div class="km-grid-option-padding">
<ul class="inline pull-right">
<li>
<a id="kmid_removeSelected"
class="km-grid-option remove"
href="#Url.Action("DeleteSelected", "Indexing", new { Area = "Admin" })"
data-target="km_grid_body"
data-redirect="#Url.Action("ManageCollections", "Indexing", new { Area = "Admin" })"
data-actiontype="submit_selected"
data-message="Do you want to continue?"><i class="icon-remove"></i> Remove Selected</a>
</li>
</ul>
</div>
}
JS-part:
$("[data-actiontype='submit_selected']").bind("click",
function () {
var $this = $(this);
var message = $this.data("message");
KM.Ajax.ShowConfirmation({ title: "Warning", message: message }, function () {
var url = $this.attr("href");
var redirect = $this.data("redirect");
var targetId = $this.data("target");
var selected = [];
var SelectedItemsIds = GetSelectedItemsIds();
$.each(SelectedItemsIds, function (Key, Item) {
selected.push({ name: "selected", value: Item });
});
//THIS PART WAS ADDED BY ME *********
var token = $("input[name='__RequestVerificationToken']").val();
if(token !== undefined && token !== "")
selected.push({name: "__RequestVerificationToken", value: token});
//*****************
$.ajax({
type: "POST",
url: url,
data: selected,
success: function (result) {
if (typeof (result) == "object") {
var json = result || {};
if (json.Success) {
var $target = $("#" + targetId);
if( settings.fullPageLoad === true )
{
location.reload();
}
else
{
$target.load( redirect, function()
{
if( settings.reloadCallback )
{
settings.reloadCallback();
}
} );
}
}
}
},
dataType: "json",
traditional: true
});
});
return false;
});
Controller:
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult DeleteSelected(Guid[] selected)
{
try
{
_presenter.Delete(selected);
return Json(new { Success = true });
}
catch (Exception ex)
{
ModelState.AddModelError(ErrorRemoveSelected, ex.Message);
var errors = ModelState.ParseErrors();
return Json(new { Success = false, Errors = errors });
}
}
I've tried to add to request data (it is my part of code) in JS-function:
var token = $("input[name='__RequestVerificationToken']").val();
if(token !== undefined && token !== "")
selected.push({name: "__RequestVerificationToken", value: token});
Also I've added [ValidateAntiForgeryToken()] to controller method.
And it works, but only one time. When I try to perform the same action on the same page - it doesn't work.
What am I doing wrong?
Thank you in advanced!

Refresh data without reloading the page

I have a function for adding likes on the page
blade.php
<a href="/article/{{ $article->id }}?type=heart" class="comments-sub-header__item like-button">
<div class="comments-sub-header__item-icon-count">
{{ $article->like_heart }}
</div>
<a href="/article/{{ $article->id }}?type=finger" class="comments-sub-header__item like-button">
<div class="comments-sub-header__item-icon-count">
{{ $article->like_finger }}
</div>
js
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
},
});
$('.like-button').on('click', function(event) {
event.preventDefault();
let href = $(this).attr('href');
$.ajax({
url: href,
type: 'POST',
success: function() {
window.location.reload();
},
});
});
});
But when I click on the like to update the data, I reload the page using window.location.reload();
Can this somehow be done without reloading the page?
This is how adding likes is implemented, they are added to cookies and stored for 24 hours
web routes
Route::post('article/{id}', 'App\Http\Controllers\ArticleController#postLike');
Article controller
public function postLike($id, Request $request) {
$article = Article::find($id);
if(!$article){
return abort(404);
}
$type = $request->input('type');
if ($article->hasLikedToday($type)) {
return response()
->json([
'message' => 'You have already liked the Article '.$article->id.' with '.$type.'.',
]);
}
$cookie = $article->setLikeCookie($type);
$article->increment("like_{$type}");
return response()
->json([
'message' => 'Liked the Article '.$article->id.' with '.$type.'.',
'cookie_json' => $cookie->getValue(),
])
->withCookie($cookie);
}
Article model
public function hasLikedToday(string $type)
{
$articleLikesJson = Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
if (!array_key_exists($this->id, $articleLikes)) {
return false;
}
if (!array_key_exists($type, $articleLikes[$this->id])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$this->id][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public function setLikeCookie(string $type)
{
$articleLikesJson = Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
$articleLikes[$this->id][$type] = now()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
Assuming those DIVs hold the number of hearts, if the response of the target page is the new number of hearts then:
success: function(data) {
targetElement.find(".comments-sub-header__item-icon-count").html(data)
}
elsewhere if you want to add +1 to current number regardless of server response:
success: function() {
var current= parseInt(targetElement.find(".comments-sub-header__item-icon-count").html());
targetElement.find(".comments-sub-header__item-icon-count").html(current+1)
}
Footnote: as the ajax request is nested inside the click function, the targetElement in my codes is the clicked element. You may get it in defferent ways e.g.
$('.like-button').on('click', function(event) {
var targetElement=$(this);
....
}
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
},
});
$('.like-button').on('click', function(event) {
event.preventDefault();
let href = $(this).attr('href');
$.ajax({
url: href,
type: 'POST',
success: function(response) {
$(this).parent(".comments-sub-header__item-icon-count").html(
parseInt($(this).parent(".comments-sub-header__item-icon-count").html()) + 1
)
// or return like or heart count from server
$(this).parent(".comments-sub-header__item-icon-count").html(response)
},
});
});
});
This should work for you
$(function () {
$.ajaxSetup({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
});
$(".like-button").on("click", function (event) {
event.preventDefault();
const likeBtn = $(this);
$.ajax({
url: likeBtn.attr("href"),
type: "POST",
success: function () {
let currentCount = likeBtn.next().text();
likeBtn.next().text(parseInt(currentCount) + 1);
},
});
});
});
You can simply add the new count to the response from your controller.
return response()
->json([
'message' => 'Liked the Article '.$article->id.' with '.$type.'.',
'cookie_json' => $cookie->getValue(),
'new_count' => $article->{"like_{$type}"},
])
->withCookie($cookie);
Now you can use the updated count as new_count from the database.
$.ajax({
url: href,
type: 'POST',
success: function (response) {
$(this).next().text(response.new_count)
},
});

Return a view from an ajax call

I have 0 experience in Ajax, and now I'm trying to get an html table to return on an ajax call.
As a result, I get the error
jquery-3.6.0.min.js:2 POST http://test.loc/%7B%7B%20url('blog/articles')%20%7D%7D 404 (Not Found)
I understand that there are still a lot of mistakes, so don't judge too much, and help in any way you can :)
Route:
Route::post('blog/articles', 'App\Http\Controllers\BlogController#articles');
Ajax on calling page:
function getBlogLists(category_id) {
var category_id = category_id;
$.ajax({
url: "{{ url('blog/articles') }}",
type: 'POST',
data: { 'category_id': category_id },
datatype: 'html',
success: function(data) {
console.log('success');
console.log(data);
document.querySelectorAll('.blog-filter__item').forEach(el => {
el.addEventListener('click', () => {
document
.querySelector('.blog-filter__item.active')
.classList.remove('active');
el.classList.add('active');
var dataFilter = $(el).attr('data-filter');
if (dataFilter == 'all') {
$('.blog-list').show();
}
else {
$('.blog-list').hide()
$(dataFilter).show()
}
});
});
},
});
}
//on page load
getBlogLists("{{ $category->id }}");
Controller:
public function articles() {
$input = Request::all();
if(Request::isMethod('post') && Request::ajax()) {
if($input['category_id']) {
$articles = Article::select('select * from blog_categories where blog_category_id = ?', array($input['category_id']));
$returnHTML = view('blog.articles')->with('articles', $articles)->render();
return response()->json( array('success', 'html'=>$returnHTML) );
}
}
}
View:
#foreach($articles as $index => $article)
<div class="blog-list category_{{ $article->blog_category_id }}">
#if ($index % 2 === 1)
<div class="blog-article blog-article--right">
<h2 class="blog-article_title">{{ $article->title }}</h2>
</div>
#else
<div class="blog-article blog-article--left">
<h2 class="blog-article_title">{{ $article->title }}</h2>
</div>
#endif
</div>
#endforeach
You have this error because you have a problem in your URL.
function getBlogLists(category_id) {
var category_id = category_id;
$.ajax({
url: "{{ url('blog/articles') }}",
Here, the url is literally {{ url('blog/articles') }}, I mean, as a string.
You are sending the request to http://test.loc/{{ url('blog/articles') }}, which once encoded gives http://test.loc/%7B%7B%20url('blog/articles')%20%7D%7D.
That's why you are getting a 404 error (not found), obviously this url doesn't exist.
First, remove the url variabilization:
function getBlogLists(category_id) {
var category_id = category_id;
$.ajax({
url: "http://test.loc/blog/articles", //or whatever your url is
Then in your controller, you just have to return the HTML and it will be inside data in your javascript success callback.
Do a simple test first:
public function articles() {
return "<h1>HelloWorld</h1>";
}
If it works with this simple "hello world", it will work with the view you are rendering as well.

Update List Model with Ajax ASP .NET MVC5

Can somebody give me a hint how to pass a list from the controller to Model list in view page after call the Action Result whit ajax in page. (Meaning update current list model with ajax call back result)?
This is my default load view page code:
#model List<ChargeSystem.Models.Message>
#foreach (var item in Model)
{
<div class="container1">
<p>#item.Msg</p>
<span class="time-right">#item.MsgDate</span>
</div>
}
</div>
<div class="divContinMsg">
<input type="text" id="txtMsg" name="txtMsg" />
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#txtMsg").keyup(function (e) {
if (e.keyCode == 13) {
$.ajax(
{
url: '/User/ajaxContactAdmin?msg=' + $("#txtMsg").val(),
type: 'Post',
data: "",
contentType: false,
success: function (result) {
//What can i do????
},
error: function () {
alert("error");
}
})
};
});
});
</script>
This is the Ajax call action result:
public ActionResult ajaxContactAdmin(string msg)
{
var result = new { model = messageRepository.Select().ToList()};
return Json(result, JsonRequestBehavior.AllowGet);
}
So, How can i refresh the model after ajax call back?
So what you would do is append the result to the existing result set.
Firstly I would add a container for easier reference, secondly you would add the item to the container:
#model List<ChargeSystem.Models.Message>
<div id="listContainer">
#foreach (var item in Model)
{
<div class="container1">
<p>#item.Msg</p>
<span class="time-right">#item.MsgDate</span>
</div>
}
</div>
</div>
<div class="divContinMsg">
<input type="text" id="txtMsg" name="txtMsg" />
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#txtMsg").keyup(function (e) {
if (e.keyCode == 13) {
$.ajax(
{
url: '/User/ajaxContactAdmin?msg=' + $("#txtMsg").val(),
type: 'Post',
data: "",
contentType: false,
success: function (result) {
$('#listContainer').append('<div class="container1">'+
'<p>' + result.Msg + '</p>'+
'<span class="time-right">' + result.MsgDate +'</span>'+
'</div>');
},
error: function () {
alert("error");
}
})
};
});
});
</script>
It looks like you want to enter information in your text box and save and update it in the view.
I think you can do this.
Here is an example:
Your Controller:
public IActionResult GetUser ()
{
var messages = context.Messages.ToList();
return View(messages);
}
[HttpPost]
public IActionResult ajaxContactAdmin(string msg)
{
var message = new Message
{
Msg = msg,
MsgDate = DateTime.Now
};
context.Add(message);
context.SaveChanges();
return Json(message);
}
Js in your View:
#section scripts{
<script>
$(document).ready(function () {
$("#txtMsg").keyup(function (e) {
if (e.keyCode == 13) {
var msg = document.getElementById("txtMsg").value
$.ajax(
{
url: '/Home/ajaxContactAdmin?msg=' + $("#txtMsg").val(),
type: 'Post',
data: { "msg": msg},
contentType: false,
success: function (message)
{
console.log(message);
window.location.reload();
},
error: function () {
alert("error");
}
})
};
});
});
</script>
}
Result display:

How do i call jquery function from the view on load if model is not null in asp.net mvc?

This is my Jquery function and view.
Jquery function will call another controller and action name which in presents the partial view.
This is my main View ...i just want to call partial view directly.
function clickAdd(compid, requestid) {
debugger;
var url1 = "/Component/AddEstimate/?compID=" + compid + "&requestID=" + requestid;
$.ajax({
type: 'POST',
url: url1,
success: function (data) {
$("#impactDevEstimateModal").find('.modal-content').removeData(data);
$('#impactDevEstimateModal').html(data);
$('#impactDevEstimateModal').show();
$("#ModalAvailableTemplate").hide();
},
statusCode: {
404: function (content) { alert('cannot find resource'); },
500: function (content) { alert('internal server error'); }
},
error: function (msg) {
//alert("Error");
$('#deStatusMessage').html(getStatusHTML(" Couldn't save data due to internal error. Please try again. ", "Error"));
}
});
}
<div style="display:none">
#{
if (Model != null && Model.Count() > 0)
{
#Html.TextBox("template", Model.FirstOrDefault().TypeOfTemplate, new { #class = "form-control input-sm" })
clickAdd(#ViewBag.CompID, #ViewBag.RequestID);//not working
}
else
{
}
}
</div>
If you wish to run a js/jquery function inside your view, try this:
<script src="~/Scripts/UpdateDetailedEstimates.js"></script>
<script>clickAdd('#ViewBag.CompID', '#ViewBag.RequestID');</script>
also you have to add '' around your #viewbag, for js/jquery to understand it.
function clickAdd(compid, requestid) {
debugger;
var url1 = "/Component/AddEstimate/?compID=" + compid + "&requestID=" + requestid;
$.ajax({
type: 'POST',
url: url1,
success: function (data) {
$("#impactDevEstimateModal").find('.modal-content').removeData(data);
$('#impactDevEstimateModal').html(data);
$('#impactDevEstimateModal').show();
$("#ModalAvailableTemplate").hide();
},
statusCode: {
404: function (content) { alert('cannot find resource'); },
500: function (content) { alert('internal server error'); }
},
error: function (msg) {
//alert("Error");
$('#deStatusMessage').html(getStatusHTML(" Couldn't save data due to internal error. Please try again. ", "Error"));
}
});
}
<div style="display:none">
#{
if (Model != null && Model.Count() > 0)
{
#Html.TextBox("template", Model.FirstOrDefault().TypeOfTemplate, new { #class = "form-control input-sm" })
<script>clickAdd('#ViewBag.CompID', '#ViewBag.RequestID');</script>
}
else
{
}
}
</div>

Categories

Resources