My problem is, that I have to implement an AJAX function to display whether the selected item is out of stock or not. However, instead of displaying my error message it kind of duplicates the site completely and I'm very, nothing I've tried seems to work.
My idea behind the code was, that I have a dropdown form with action set to a controller (Webservlet) that handles both doGet and doPost, and an onchange event showing to a javascript function which invokes the AJAX stuff (You can see I'm not very confident in these aspects, I don't know nearly enough about it).
The JSP part that is relevant would be this:
<%#page contentType="text/html" pageEncoding="UTF-8" import="PCConfigurator.*"%>
<%
session.setMaxInactiveInterval(0);
ConfController ctrl = new ConfController();
%>
...
<script type="text/javascript">
var xmlHttpObject = new XMLHttpRequest();
function checkArticle(selectedArticleId) {
var url = '?id=' + selectedArticleId.value;
xmlHttpObject.open('GET', url);
xmlHttpObject.onreadystatechange = handleStateChange;
xmlHttpObject.send();
}
function handleStateChange() {
if (this.readyState == 4 && this.status == 200) {
var response = this.responseText;
var result = document.getElementById("errorDiv");
result.innerHTML = response;
}
}
</script>
<form method="POST" action="ConfController" >
<table>
<h1>PC Konfigurator GO Inc.</h1>
<tr>
<td><br><br></td>
</tr>
<tr>
<td>Welchen Prozessor wollen Sie haben?:</td>
<td><select name="cpuId" onchange="checkArticle(this)">
<%
for (Article article : ctrl.getCertainArticles("CPU")) {
out.print("<option value=\"" + article.getId() + "\">" + article.getName() + "</option>");
}
%>
</select>
</td>
</tr>
...
And the Controller looks something like this:
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
int id = Integer.parseInt(req.getQueryString().split("=")[1]);
if (findArticle(id).getCapacity() < 1) {
resp.getWriter().write("<p><font color=\"red\">Leider ist dieser Prozessor nicht mehr verfügbar.</font></p>");
} else {
resp.getWriter().write("");
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
This is how the site looks on startup. So far so good.
But as soon as I choose another item in the dropdown, well, this happens...
I mean at least the id is right.
Its just the stupid AJAX I cant get to work.
In your code you did not specified the controller for your AJAX request. This is the reason you are getting same as the response and the response shown using AJAX.
In console you can also see the full url which is being called AJAX request by hovering on the ?id=2.
function checkArticle(selectedArticleId) {
var url = 'myController?id=' + selectedArticleId.value;
xmlHttpObject.open('GET', url);
xmlHttpObject.onreadystatechange = handleStateChange;
xmlHttpObject.send();
}
In above code replace myController with your actual controller name which points to your servlet.
Related
I am aware that this is a recurring question, for all web programming languages. I have spent five hours trying to apply solutions found here without success, which is why I write this question.
What I want:
I have two selectors, both when loading the page are filled with information directly from the database successfully.
If I select an option from the first selector (selectSchraubfall) I want the second selector (selectWorkplace) to update, showing only those possible results for the first selector.
What I did:
Created the selectors inside the jsp getting the information from a servlet that executes a sql query ✔.
Created the onChange event listener for the first selector ✔.
Created a js function with an Ajax call to make a new query from the controller and get a filtered list of options for the second select ✔.
Inside the success function I tried to inject the result of the Ajax call into the second select via .html(), it does not work. How can I inject JSTL? In other words, how can I inject the content of wpFilteredList in selectWorkplace? ✕
What I tried:
Using JSON -> Didn't work ✕
Using JAVA scriplets inside the JSP -> Didn't work ✕
JSP
html:
<div class="row">
<div class="col-md">
<label style="font-size: 20px;">Schraubfall ID: </label>
<select id="selectSchraubfall" name="selectSchraubfall" form="formResult" class="form-control" >
<option>Select ID</option>
<c:forEach items="${screwdriverlist}" var="screwdriverlist">
<option><c:out value="${screwdriverlist.screwdriverid}" /></option>
</c:forEach>
</select>
</div>
<div class="col-md">
<label style="font-size: 20px;">Workplace: </label>
<select id="selectWorkplace" name="selectWorkplace" form="formResult" class="form-control">
<option>Select workplace</option>
<c:forEach items="${workplaceList}" var="workplaceList">
<option><c:out value="${workplaceList.workplacename}" /></option>
</c:forEach>
</select>
</div>
</div>
JS:
var options="";
$("#selectSchraubfall").on('change',function(){
var value=$(this).val();
resultSelectValue('Schraubfall', value);
});
function resultSelectValue(columnName, value) {
// Statements
var params = {};
params.colname = columnName;
params.valuecol = value;
$.ajax({
type: "GET",
url: 'ResultSelectValuesController',
data: params,
success: function (data) {
var workplaceArray = [];
$("#selectWorkplace").empty().html();
<c:forEach items="${wpFilteredList}" var="wpFilteredList">
//<option value="${wpFilteredList.name}"></option>
workplaceArray.push('"${wpFilteredList.name}"');
</c:forEach>
$("#selectWorkplace").html(workplaceArray); //I know this is not correct but how can I do something similar using the wpFilteredList?
},
error : function(ex) {
swal("Error", "Error loading workplace info " + ex.Message, "error");
}
});
}
Java (ResultSelectValuesController)
#Override
public void processMethodGET(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String colname = request.getParameter("colname");
String valuecol = request.getParameter("valuecol");
if(colname.contains("Schraubfall")) {
//GET WORKPLACES
workplacesfilteredlist = wcdao.workplacesListFilter(colname, valuecol);
request.setAttribute("wpFilteredList", workplacesfilteredlist);
}
request.getRequestDispatcher("/Views/Results/ResultPage.jsp").forward(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
processError(e, request, response);
}
}
Below block is JSTL server side interpolation. Javascript can't process this syntax.
You need to replace below JSTL code with javascript version which pushes the data from ajax requests response to workplaceArray.
<c:forEach items="${wpFilteredList}" var="wpFilteredList">
//<option value="${wpFilteredList.name}"></option>
workplaceArray.push('"${wpFilteredList.name}"');
</c:forEach>
The code below is adds new data to the select element as option elements. You need to replace data as your response type.
data.forEach(workplace => {
$('#selectWorkplace').append($('<option>', {
value: workplace,
text: workplace
})
})
After the changes you don't need the below code anymore.
$("#selectWorkplace").html(workplaceArray);
Finally I solved the problem by myself, It worked using Gson. Basically I am returning an Array of Arrays and I manipulate the data as I want in the JSP.
The code now:
JSP
function resultSelectValue(columnName, value) {
// Statements
var params = {};
params.colname = columnName;
params.valuecol = value;
$.ajax({
type: "GET",
url: 'ResultSelectValuesController',
data: params,
success: function (data) {
$( "#selectWorkplace" ).empty();
$( "#selectSchraubfall").empty();
var htmlWorkplace = "<option>Seleccionar Workplace</option>";
var htmlsf = "<option>Todos los Schraubfalls</option>";
for (i = 0; i < data.length; i++) {
for(j = 0; j < data[i].length; j++){
alert(data[i][j]);
if(i == 0) {
htmlWorkplace += "<option>"+data[i][j]+"</option>";
}
if(i == 1){
if(data[i][j] != 'null' && data[i][j] != null){
htmlsf += "<option>"+data[i][j]+"</option>";
}
}
}
}
$( "#selectWorkplace" ).html(htmlWorkplace);
$( "#selectSchraubfall").html(htmlsf);
JAVA
#Override
public void processMethodGET(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
response.setContentType("application/json");
String colname = request.getParameter("colname");
String valuecol = request.getParameter("valuecol");
if(colname.contains("Atornillador")) {
//GET WORKPLACES
wpfilteredlist = wcdao.workplacesListFilter(colname, valuecol);
//GET SF
sffilteredlist = sfdao.SFListFiltered(colname, valuecol);
ArrayList<ArrayList<String>> listGet = new ArrayList<ArrayList<String>>();
ArrayList<String> wpList = new ArrayList<String>();
ArrayList<String> sfLista = new ArrayList<String>();
for (int i = 0; i < wpfilteredlist.size(); i++) {
wpList.add(wpfilteredlist.get(i).getName());
}
for(int i = 0; i < sffilteredlist.size(); i++) {
sfList.add(sffilteredlist.get(i).getSfname());
}
listGet.add(wpList);
listGet.add(sfList);
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(listGet);
PrintWriter out = response.getWriter();
out.print(element);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
processError(e, request, response);
}
}
I'm trying to make a client-server application where from the client I send a request through a JSON object to the server to register. The thing is I should get another JSON with an "OK" field (which is actually being sent) but for some reason the client keeps going to the .fail function instead of the .done one (sorry if some of used terms are not very accurate, I'm new to this).
So I'll this is my code incase you can check if there's anything wrong causing this:
Client JS:
define(['ojs/ojcore', 'knockout', 'jquery', 'appController', 'jquery', 'ojs/ojknockout', 'ojs/ojinputtext'],
function(oj, ko, $, app) {
function RegistrarseViewModel() {
var self = this;
this.email = ko.observable();
this.pwd1 = ko.observable();
this.pwd2 = ko.observable();
this.registrar = function(){
alert("Se ha mandado el registro");
var p = {tipo:"Registrarse",email: this.email(), pwd1:this.pwd1(), pwd2:this.pwd2()};
$.ajax({
type:"POST",
url:"http://localhost:8080/ServidorWeb/Registrarse.jsp",
data: "p=" + JSON.stringify(p)
}).done(function(data, textStatus, jqXHR){
alert("Comprobando tipo");
if (data.tipo == "OK"){
//window.location="index.html?root=juegos"
sessionStorage.jugador=self.email();
app.router.go("login");
alert("Registro correcto");
}else
alert(respuesta.texto)
}).fail(function() {
alert("Sorry. Server unavailable. lol ");
});
}
this.cancelar = function(){
app.router.go("login");
}
}
return new RegistrarseViewModel();
}
);
Server JSP:
<%# page language="java" contentType="application/json ; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# page import= "org.json.*,dominio.Manager"%>
<%
String p = request.getParameter("p");
JSONObject resultado=new JSONObject();
try{
JSONObject jso= new JSONObject(p);
if(!jso.getString("tipo").equals("Registrarse")){
resultado.put("tipo","NOK");
resultado.put("texto","Mensaje inesperado");
}else{
String email=jso.getString("email");
String pwd1=jso.getString("pwd1");
String pwd2=jso.getString("pwd2");
Manager.get().registrarse(email,pwd1,pwd2);
resultado.put("tipo","OK");
resultado.put("texto","Te has registrado con el email " + email);
}
}
catch(Exception e){
resultado.put("tipo","NOK");
resultado.put("texto","Mensaje Inesperadoo");
}
%>
<%=resultado.toString()%>
After executing Manager.get().registrarse(email,pwd1,pwd2); (which is the logic to register into a MongoDB) it just continues with the resultado.put("tipo","OK"); line which means the problem isn't in there.
Also if I send the request http://localhost:8080/ServidorWeb/Registrarse.jsp?p=%7Btipo:%22Registrarse%22,email:%2233%22,pwd1:%2220%22,pwd2:%2220%22%7D from a browser like Google Chrome it prints this: {"texto":"Te has registrado con el email 33","tipo":"OK"} but from the real client it just won't get into the .done function, idk why.
I really hope you can help me.
Thanks in advance.
EDIT 1: Added the server response from the browser console IMAGE
Okay I solved this finally.
I had to add this line at the beggining of the .jsp, this was an issu with TomCat which has something like 2 machines and without this line it doesn't allow communication among different machines because of security reasons it seems.
response.setHeader("Access-Control-Allow-Origin", "*");
if you use jquery the correct way is use serialize function from jquery
https://api.jquery.com/serialize/
first give a id for you form something like :
`
$("#myform form").submit(function(event){
event.preventDefault();
var sendData = $("#myform form").serialize();
$.post("your-PHP-handler.php", sendData);
});
<form id="myform" method="post" action="your-PHP-handler.php">
<input type="name" placeholder="name">
<input type="name" placeholder="age">
<input type="name" placeholder="address">
<button type="submit">send</button>
</form>
`
note when you submit your form via javascript the serialization jquery get all inputs in your post end send all together you cam handler the response php inside of $.post() you can make many things with this consulting jquery documentation.
anyway the basic is there , get everything inside my form and send to my php file
I am seeing odd behavior with the code here.
Client-side (Javascript):
<input type="text" id="userid" placeholder="UserID" /><br />
<input type="button" id="ping" value="Ping" />
<script>
var es = new EventSource('/home/message');
es.onmessage = function (e) {
console.log(e.data);
};
es.onerror = function () {
console.log(arguments);
};
$(function () {
$('#ping').on('click', function () {
$.post('/home/ping', {
UserID: parseInt($('#userid').val()) || 0
});
});
});
</script>
Server-side (C#):
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Web.Mvc;
using Newtonsoft.Json;
namespace EventSourceTest2.Controllers {
public class PingData {
public int UserID { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
}
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
static ConcurrentQueue<PingData> pings = new ConcurrentQueue<PingData>();
public void Ping(int userID) {
pings.Enqueue(new PingData { UserID = userID });
}
public void Message() {
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
var msg = "data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n";
Response.Write(msg);
}
Response.Flush();
Thread.Sleep(1000);
} while (true);
}
}
}
Once I've pressed ping to add a new item to the pings queue, the loop inside the Message method picks the new item up and issues an event, via Response.Write (confirmed using Debug.Print on the server). However, the browser doesn't trigger onmessage until I press ping a second time, and the browser issues another event; at which point the data from the first event reaches onmessage.
How can I fix this?
To clarify, this is the behavior I would expect:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
EventSource calls onmessage
This is what is actually happening:
Client Server
-------------------------------------------------------------------
Press Ping button
XHR to /home/ping
Eneque new item to pings
Message loop issues server-sent event
(Nothing happens)
Press Ping button again
New XHR to /home/ping
EventSource calls onmessage with previous event data
(While running in Chrome the message request is listed in the Network tab as always pending. I'm not sure if this is the normal behavior of server-sent events, or perhaps it's related to the issue.)
Edit
The string representation of the msg variable after Response.Write looks like this:
"data:{\"UserID\":105,\"Date\":\"2016-03-11T04:20:24.1854996+02:00\"}\n\n"
very clearly including the newlines.
This isn't an answer per say but hopefully it will lead one. I was able to get it working with the following code.
public void Ping(int id)
{
pings.Enqueue(new PingData { ID = id });
Response.ContentType = "text/plain";
Response.Write("id received");
}
public void Message()
{
int count = 0;
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
Response.ClearContent();
Response.Write("data:" + nextPing.ID.ToString() + " - " + nextPing.Date.ToLongTimeString() + "\n\n");
Response.Write("event:time" + "\n" + "data:" + DateTime.Now.ToLongTimeString() + "\n\n");
count = 0;
Response.Flush();
}
if (!Response.IsClientConnected){break;}
Thread.Sleep(1000);
count++;
} while (count < 30); //end after 30 seconds of no pings
}
The line of code that makes the difference is the second Response.Write. The message doesn't appear in the browser until the next ping similar to your issue, but the ping always appears. Without that line the ping will appear only after the next ping, or once my 30 second counter runs out.
The missing message appearing after the 30 second timer leads me to conclude that this is either a .Net issue, or there's something we're missing. It doesn't seem to be an event source issue because the message appears on a server event, and I've had no trouble doing SSE with PHP.
For reference, here's the JavaScript and HTML I used to test with.
<input type="text" id="pingid" placeholder="ID" /><br />
<input type="button" id="ping" value="Ping" />
<div id="timeresponse"></div>
<div id="pingresponse"></div>
<script>
var es = new EventSource('/Home/Message');
es.onmessage = function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onmessage<br/>";
};
es.addEventListener("ping", function (e) {
console.log(e.data);
document.getElementById('pingresponse').innerHTML += e.data + " - onping<br/>";
}, false);
es.addEventListener("time", function (e) {
document.getElementById('timeresponse').innerHTML = e.data;
}, false);
es.onerror = function () {
console.log(arguments);
console.log("event source closed");
es.close();
};
window.onload = function(){
document.getElementById('ping').onclick = function () {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
console.log(this.responseText);
};
var url = '/Home/Ping?id=' + document.getElementById('pingid').value;
xmlhttp.open("GET", url);
xmlhttp.send();
};
};
</script>
Since an eventstream is just text data, missing the double line break before the first event is written to response could affect the client. The example from mdn docs suggests
header("Content-Type: text/event-stream\n\n");
Which could be applied apply to .NET response handling (note the side effects of Response.ClearContent()).
If it feels too hacky, you could start your stream with a keep-alive comment (if you want to avoid timing out you may have to send comments periodically):
: just a keep-alive comment followed by two line-breaks, Response.Write me first
I'm not sure if this will work because I can't try it now, but what about to add an End?:
Response.Flush();
Response.End();
The default behavior of .net is to serialize access to session state. It blocks parallel execution. Requests are processed sequentially and access to session state is exclusive for the session. You can override the default state per class.
[SessionState(SessionStateBehavior.Disabled)]
public class MyPulsingController
{
}
There is an illustration of this in the question here.
EDIT: Would you please try creating the object first and then passing it to Enqueue? As in:
PingData myData = new PingData { UserID = userID };
pings.Enqueue(myData);
There might be something strange going on where Dequeue thinks it's done the job but the the PingData object isn't properly constructed yet.
Also can we try console.log("I made it to the function") instead of console.log(e.data).
---- PREVIOUS INFORMATION REQUESTED BELOW ----
Please make sure that the server Debug.Print confirms this line of code:
Response.Write("data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n");
Is actually executed? Please double check this. If you can capture the server sent response then can we see what it is?
Also could we see what browsers you've tested on? Not all browsers support server events.
Here is the solution of the problem. Thanks to all, and special thanks to Alessandro G. for the private help.
I made load() on jsp URL thinking to load the elaboration with permutation.
The right way is to do load() on the SERVLET URL, passing parameterized data from the form. load() does a GET with data to java servlet, the java servlet elaborates the permutation and his response contain the jsp used as template to print the HTML code with permutations
$(document).ready(function(){
$("form").submit(function(event){
console.log("submit effettuato");
event.preventDefault();
var formData = $(this).serialize();
console.log(formData);
$("#aggiornare").load( "anagrammiajax", formData , function(responseTxt, statusTxt, xhr){
if(statusTxt=="success"){
alert("contenuto esterno cariato correttamente");
}
if(statusTxt=="error"){
alert("error: " + xhr.status + ": " + xhr.statusText);
}
});
});
});
i'm studing web application and i'm trying to create an application to display permutations of a string.
I use an html page called "index.html" with a form that send the word to servlet
the servelt is called "anagrammiajax" and it works correctly
the servlet elaborates the permutations ad dispatch them to jsp page called "anagrammi- partial.jsp
the jsp page just use a foreach to print all the permutations
i want use ajax load() method in the index.html page to show into a div the content of the jsp page
problems:
i don't want a redirect to jsp page after servlet elaboration, but i wont show again the idex.html wht the updated div (maybe with another redirect from jsp to index.html and adding a setInterval method to auto refresh the page with a timer and load the content?)
the jquery load() method don't load the content in the div from jsp page (the permutations printed by forEach) and it returns me a 0 error
please, help me to resolve it and
here is my code:
index.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Anagrammi su JSP usando JSTL, jQuery, AJAX</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript" src="update.js"></script>
</head>
<body>
<h1>Anagrammi su JSP usando JSTL, jQuery e AJAX</h1>
<p>visualizza gli anagrammi (permutazioni) della parola inserita</p>
<div>
<form action="anagrammiajax" name="anagrammi" method="post">
<input type="text" name="parola">
<input id="submit" type="submit" value="genera anagrammi">
</form>
</div>
<div>
<h2>Risultati</h2>
<h3>pagina aggiornata con AJAX e jQuery</h3>
<div id="aggiornare">
</div>
</div>
</body>
</html>
update.js code:
$(document).ready(function(){
$("#submit").click(function(){
alert("click");
$("#aggiornare").load("anagrammi-partial.jsp", function(responseTxt, statusTxt, xhr){
if(statusTxt=="success"){
alert("contenuto esterno cariato correttamente");
}
if(statusTxt=="error"){
alert("error: " + xhr.status + ": " + xhr.statusText);
}
});
});
});
here is the servlet code:
package anagrammiAjax;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.*;
#SuppressWarnings("serial")
public class AnagrammiAjaxServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String parola = req.getParameter("parola");
parola = parola.toLowerCase();
System.out.println(parola);
ArrayList<String> anagrammi = permutations(parola);
for(int i=0; i<=anagrammi.size()-1; i++){
System.out.println(anagrammi.get(i));
}
req.setAttribute("parola", parola);
req.setAttribute("anagrammi", anagrammi);
try {
getServletContext().getRequestDispatcher("/anagrammi-partial.jsp").include(req, resp);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static ArrayList<String> permutations(String s) {
ArrayList<String> ret = new ArrayList<String>();
permutation(s.toCharArray(), 0, ret);
return ret;
}
public static void permutation(char[] arr, int pos, ArrayList<String> list){
if(arr.length - pos == 1)
list.add(new String(arr));
else
for(int i = pos; i < arr.length; i++){
swap(arr, pos, i);
permutation(arr, pos+1, list);
swap(arr, pos, i);
}
}
public static void swap(char[] arr, int pos1, int pos2){
char h = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = h;
}
}
and in the end the jsp code:
<%# page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<c:forEach items="${anagrammi }" var="indice">
<c:out value="${indice}"/>
</c:forEach>
You are triggering the Ajax request when the user clicks on a submit button.
The JavaScript runs, then the form is submitted, a new page loads and the execution environment for the JavaScript goes away and is a replaced by a new one.
You need to stop the form from submitting.
$(document).ready(function(){
// Capture the event object in an argument
$("#submit").click(function(evt) {
// Prevent the default action
evt.preventDefault();
Try with this code, and use "console.log" and browser's devtools instead of "alert" for debugging
$(document).ready(function(){
$("form").submit(function(event){
console.log("submit form");
event.preventDefault();
var thisForm = $(this);
var jqxhr = $.post("anagrammi-partial.jsp", thisForm.serialize())
.done(function(data){
console.log("contenuto esterno caricato correttamente");
$("#aggiornare").html(data);
})
.fail(function(xhr, textStatus){
console.log("error: "+textStatus );
})
.always(function(){
console.log("finished");
});
});
});
I'm trying to write a straightforward comment poster. I have this code in the controller:
[HttpPost]
[ValidateInput(false)]
public ViewResult Comments(MemberData md, long EntryId, string Comment, long LastId = 0)
{
bool isModerated = true;
bool isLoggedIn = GenesisRepository.IsNotGuest(md.MemberGUID);
bool isCommentAllowed = GenesisRepository.IsPermissionAssigned(md.MemberGUID, "Comments", "Create");
// Moderate comment?
if (moderateGuestComments == false && isLoggedIn == false) isModerated = false;
if (moderateMemberComments == false && isLoggedIn) isModerated = false;
long memberId = (from m in GenesisRepository.Member
where m.MemberGUID == md.MemberGUID
select m.MemberID)
.FirstOrDefault();
if (
EntryId > 0
&& !string.IsNullOrEmpty(Comment)
&& memberId > 0
&& isCommentAllowed)
{
Comments comment = new Comments {
Comment = Comment,
Date = DateTime.Now,
isActive = isModerated ? false : true,
MemberID = memberId,
StreamEntryID = EntryId,
};
if (GenesisRepository.SaveComment(comment))
{
List<Comments> comments = new List<Comments>();
comments = (from c in GenesisRepository.Comments
where c.StreamEntryID == EntryId
&& c.comID > LastId
select c
).ToList();
return View("DisplayComments", comments);
}
}
return View("CommentError", "Unable to post comment.");
}
When everything is fine and the action returns return View("DisplayComments", comments); the $.post() success function is triggered. But, When the action returns return View("CommentError", "Unable to post comment."); The $.post() ajax fails. I don't understand why the $.post() cares which view I'm returning.
Here's my Javascript:
<script type="text/javascript">
$(document).ready(function () {
$("#comments").ajaxError(function (event, request, settings) {
alert("Error requesting page " + settings.url);
});
$("button#submitComment").click(function () {
var commentList = $("#comments");
var lastId = $(".comment h4").last().attr("id");
var commentData = "EntryId=" + $("input#EntryID").val()
+ "&Comment=" + $("textarea#Comment").val()
+ "&LastId=" + lastId;
$.post(
"/find/Comments/Comments",
commentData,
function (data) {
alert("success");
alert(data);
if ($(data).filter(".error").length > 0) {
error = $(data);
$(this).after(error);
}
else {
newComments = $(data);
newComments.filter(".comment").css('display', 'none');
alert(newComments);
commentList.append(newComments);
$(".comment").each(function () {
$(this).slideDown("fast")
});
$("#Comment").attr("value", "");
}
}
);
});
});
</script>
What about this could cause the ajax to fail?
Here's what the two views look like:
View("DisplayComments", comments); (works)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<Genesis.Domain.Entities.Comments>>" %>
<% foreach (var item in Model) %>
<% { %>
<div class="comment" style="background:#eee; border:1px solid gray; padding:10px 10px 0 10px; margin-bottom:20px;">
<h4 id="<%:item.comID %>"><%: item.Member.ScreenName%> commented on <%: String.Format("{0:f}", item.Date)%></h4>
<p>
<%: item.Comment%>
</p>
</div>
<% } %>
View("CommentError", "Unable to post comment."); (does not work)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<div class="error">
<%:Model%>
</div>
What about this could cause the ajax post to fail?
If the ajaxError function is triggered this strongly indicates that your controller action returns a status code different than 200, probably 500 which is a strong indication that your controller action throws an exception before ever reaching the last line and be able to return a view.
So here are the steps to do:
Use FireBug
Look at what your server sends as response to the AJAX request
Analyze the response status code and the response contents
Alternative approach:
Put a breakpoint in your controller action
Hit F5
When the controller action is hit step through your code
Observe exactly what happens
Remark: I would very strongly recommend you properly encoding your AJAX input. So instead of:
var commentData = "EntryId=" + $("input#EntryID").val()
+ "&Comment=" + $("textarea#Comment").val()
+ "&LastId=" + lastId;
you definitely should:
var commentData = $.param({
EntryId: $("input#EntryID").val(),
Comment: $("textarea#Comment").val(),
LastId: lastId
});
Note that everytime you use the +, & and = signs when dealing with querystring parameters (no matter what language you are using) you are doing it wrong.