custom events with server sent events - javascript

I am trying to utilize server sent events to handle the client side of some async operations im doing server side. Scroll to the bottom to see the final question.
What I have is an web app that needs a global search. The returns can be massive and take some time as they are actually sent to a webservice and then returned as XML.
I am trying to use server sent events (javascript: EventSource) to enable this. It works great for just one event but if I want to do a bunch of different events it gets a little weird, at least for me. I am new to SSE.
so far I have done this:
var sse = new EventSource('testsse.aspx');
function init() {
sse.onopen = function (e) {
console.log(e.data);
};
sse.onmessage = function (e) {
//if data has been returned the "data:" field will not be empty so we know the server operation is complete.
if (e.data.length>0) {
$('#rgCcr').kendoGrid({
dataSource: JSON.parse(e.data)
});
sse.close();
}
console.log("message: " + e.data);
};
$(document).ready(function() {
init();
});
on the server I have an aspx page that is building the json strings. as I mentioned I have it working great if I just use the standard "data: my message\n\n" format. What I need to do is get a few more pieces of info in there.
The spec for SSE says that you can specify an event to fire. I cant get this to work so far though.
in my aspx I am building the string like this:
json = string.Format("id:{0}\n event:myEvent\n data:{1}\n\n", id, ser.Serialize(ccrData));
I have tried creating a custom event but I am not sure what to bind it to in order to catch it.
On the page I have 5 different areas that are being search as part of the global search. Each is executed as an async task on the server and as they complete they will send the data back to the client. once the client detects the event has submitted data it will close the listener and add the data results to the kendo grid.
How can I use the event field of the SSE to tell the difference between what is coming back?

Rather than using the "onmessage" function, you could try registering an event listener. That way you can choose to listen to a particular event type.
es = new EventSource('/events', withCredentials: true);
es.addEventListener("open", function (e) {
alert("Connecting...");
});
es.addEventListener("error", function (e) {
alert("Error");
});
es.addEventListener("myEvent", function (e) {
alert("MyEvent");
alert(e.data);
});
There's great documentation here:
http://html5doctor.com/server-sent-events/

Related

Stop AJAX XHR call but still continue with PHP

Good afternoon,
I have the following functions that shows and hides a page busy loader:
busyStatusDelay = 1000; //milliseconds
var timer = null;
var show = false;
function busyShow(nodelay,delay) {
timer = setTimeout('busyDelayShow()',busyStatusDelay);
}
function busyDelayShow() {
if ($.active > 0) {
$('#json-overlay').css('display', 'table');
show = true;
}
}
function busyHide() {
clearTimeout(timer);
timer = null;
show = false;
$('#json-overlay').css('display', 'none');
}
This works great for normal ajax queries, we however have a new function that should send emails with SMTP, but this SMTP connection takes a few seconds too long to connect and send the emails.
To avoid this I want the ajax function to not trigger this loader, the function does not call the function to open the loader, but the issue is that when another function gets called that should open the loader, it picks up that there is an active connection so the loader comes back up and does not go away.
I tried to use the following so that the JS does not see it as an active request:
xhr.abort(); busyHide();
but when the ajax gets aborted the php aborts with it.
Note that the functions to send the emails should run in the background and should not wait for a response.
I have been searching for a way to disconnect from the server request without affecting the server's functions running and send the email.
I saw ignore_user_abort in another post so will be doing some reading up on this to see if this will work without affecting the rest of the system.
Thanks in advance for any tips on how to continue!
A good approach to this would be to execute your SMTP as a background process using some sort of queuing mechanism. So basically, whenever a JS triggers AJAX to mail, the PHP push the email request to a queue and send a response back to the XHR immediately. This way, your AJAX execution won't be blocked for long.
If you are using some sort of PHP framework like Laravel, it makes easier to manage queues otherwise have a look at this post.

Can I do DOM manipulation within an Express POST request?

I'm working with basic HTML/CSS frontend, I currently have a landing page with a form on it that sends some data to a database. When the request is done, it is expecting some sort of response. In this case, I am re-rendering the page, however, I want to replace the form with some sort of a thank you message, something so the user knows that it has sent correctly. I have tried the solution of simply having a separate near identical page with the form removed and replaced, however, this kind of code cloning seems like an inefficient way to do it. Is there a way I could do some sort of front-end DOM manipulation from within my node app instead?
Generally, if you want to manipulate how the DOM looks server side you would need to render your entire page server side and then send it to the front end.
If you want to simply manipulate the DOM after a request is received on the front end, whic is a pretty regular practice for this type of stuff; regardless of the back end language(s) used, you can:
Submit form
Let user know form is submitting to server (Best practice for UX)
Once you receive your response, manipulate the DOM however you would like
For this use case, I've taken advantage of the async/await syntactical pattern which will allow you to wait for a response while not ending up in a nested callback pattern.
The attached snipped will fake a request to the server through a set timeout value, and echo what you put into the form back to the page. It's on a three second delay and uses AJAX to make the request.
*You can simplify this code by removing some logging and comments, but I've made it more verbose than necessary for learning purposes.
**I've purposely put the submit button outside of the form element so that it does not auto-post on submit. If you want to submit this way, you can use event.preventDefault() within the function, catch the event before it bubbles, and do this instead. Either way will work fine.
async function getDataAsync0(data) {
return new Promise(async (res) => {
setTimeout(()=>{
res(data);
},3000)
});
}
$(`#submitButton`).click(async () => {
// Create div to display what's going on
let statusAreaElement = $(`#statusArea`);
// Submit Event
statusAreaElement.html(`Submitted... Waiting for response...`);
// Cache input element
let inputElement = $(`#input01`);
// Cache form element
let formWrapperElement = $(`#formWrapper`);
// Cache success message div
let successMessageElement = $(`#successMessage`);
// Get value
let value = inputElement.val();
// Send value, await response;
let response = await getDataAsync0(value);
statusAreaElement.html(`Response returned -> ${response}`)
// Clear input element
inputElement.val(``);
// Hide form, show success message
formWrapperElement.hide();
successMessageElement.show();
})
#statusArea {
position: absolute;
left: 0;
bottom: 0;
}
#successMessage {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="formWrapper">
<form>
<label for="input01">Form Input</label>
<input id="input01" type="text">
</form>
<button id="submitButton">
Submit Form
</button>
</div>
<div id="successMessage">
Thanks for your submission!
</div>
<div id="statusArea">
</div>
JSFiddle offers an echo service so I've also written the same code into a fiddle so you can see it actually call the server and echo back the response.
Here is that link:
https://jsfiddle.net/stickmanray/ug3mvjq0/37/
This code pattern should be all you need for what you are trying to do. Again, this request is also over AJAX so the DOM does not need to completely reload; if you are actually going to be making a regular post (without AJAX) to the server and then reload the page afterwards, you can do the same thing - or simply construct the new page you wanted to send to them server side and then redirect them from there.
I hope this helps!
Can I do DOM manipulation within an Express POST request?
No. The server builds up a response (a big chunk of html), that gets sent to the client which parses it and builds up the DOM. You cannot directly work with that from the server.
However you can:
1) Modify the html the server sends (have a look at express.render)
2) Run a clientide script that opens a connection to the server (websockets, AJAX) and then mutate the DOM there when the server sends something.

TcpClient don't receive any data with ajax call

I'm struggling to find out why TcpClient don't receive any data in server side if it has called through ajax.
However, if I put breakpoint in my server side code it works fine even if I have called it with ajax.
I also investigated to find out if my JavaScript function is asynchronous but it seems my JavaScript function is fine.
JavaScript function:
$('#btnGO').click(function () {
var url = 'Home/Command';
var data = { Location: $('#Location').val() };
$.when($.getJSON(url, data)).then(function (result) {
$('.Console').html(result);
});
});
Server side:
TcpClient tc = new TcpClient("Host Address", 23);
return Json(tc.Connected + " " + tc.Available, JsonRequestBehavior.AllowGet);
Output if I put breakpoint in serverside:
true 22
Output if I don't put breakpoint in serverside:
true 0
I think you'd want to call GetStream(), and then call Read() on the returned NetworkStream. Read() is blocking, and won't allow your action method to return prematurely. Right now, there are no blocking calls to prevent your action method from instantly returning (faster than your tcp client receives data), which is why you get 22 when you put in a break point - it doesn't instantly return. It seems awkward that your UI responsiveness depends on somebody sending data to your API via a socket though....
let me emphasize this more: It's really strange what you're doing. Your UI will be waiting for a client to send data to your API via a socket. Having said that, check out the following link: https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.getstream(v=vs.110).aspx

Asp.net MVC, calling C# method from client-side by onclick JS event

I got "MultiLanguageProvider" which is ordinary C# class, not Controller or Model. The idea is when user clicks Change language - it must call back server-side void ChangedLanguage() on MultiLanguageProvider instance. This doesn't work at all:
#MultiLanguageProvider.Instance.SelectAppropriate("на русском", "in english")
- 'cause all the code inside #{ } get executed immideately - at the time of page-load. I am not informed about AJAX, so maybe someone of u can show me the right direction to do this simply job?
I don't understand which one you are trying to invoke on anchor tag click. But if I understand the essence of your question, you are trying to call some server side method to change the language, and here I assume you want to save the language selection that was made on user interface (UI). If this is what you are looking, on client side, you do the changes suggested by Stephen Muecke. On server side, you need to add a [HTTPPOST] action method on controller something like:
public ActionResult SwapLanguage(LanguageViewModel languageViewModel)
{
//do the save action => like saving to database
return Json(new { data = {urlToRedirt: "/someUrl_GeneratedVia_UrlHelper"},
status = "success",
message = "Language Changed Successfully" }, JsonRequestBehavior.AllowGet);
}
}
On Client side:
$('#swaplanguage).on('click', function(event) {
event.preventDefault();
$.post( '#Url.Action("SwapLanguage")', function( data ) {
// Handle the server side response here.
// Like if you want to redirect, use something like:
// window.location = data.urlToRedirt;
});
}
Of course, you need to handle error conditions on both client as well as server side.
If you don't want to save anything, and you just want to redirect user to some url based on the language user selects, then your onclick event handler is something like:
$('#swaplanguage).on('click', function(event) {
urlToRedirect = 'url_to_redirect' + '/' + $('#languageDropDownId').val();
window.location = urlToRedirect;
}
Finally, your anchor tag is:
<a id="swaplanguage">Change Language</a>
Hope that helps.

How to add parameters to a #Url.Action() call from JavaScript on click

I have a link that when clicked needs to call a controller action with certain data which must be retrieved via JavaScript. The action will be returning a FileStreamResult.
I looked at #Url.Action but I couldn't figure out how (or even if) I could pass value dictionary stuff which had to be retrieved via JS.
So then I went with a $.post from a click handler. The problem I'm having is that I'm not sure what to do in my success: function() to return the file stream result to the user. Or even if I can.
So any help on how you would do something like this would be great..
So then I went with a $.post from a click handler. The problem I'm having is that I'm not sure what to do in my success: function() to return the file stream result to the user. Or even if I can.
Exactly. You can't do much with a received byte in javascritpt: obviously you cannot save it on the client computer nor pass it to some external program on the client. So don't call actions that are supposed to return files using AJAX. For those actions you should use normal links:
#Html.ActionLink("download file", "download", new { id = 123 })
and let the user decide what to do with the file. You could play with the Content-Disposition header and set it to either inline or attachment depending on whether you want the file to be opened with the default associated program inside the browser or prompt the user with a Save File dialog.
UPDATE:
It seems that I have misunderstood the question. If you want to append parameters to an existing link you could subscribe for the click event in javascript and modify the href by appending the necessary parameters to the query string:
$(function() {
$('#mylink').click(function() {
var someValue = 'value of parameter';
$(this).attr('href', this.href + '?paramName=' + encodeURIComponent(someValue));
return true;
});
});
Instead of going with a post, I'd go with associate a JQuery on click handler of the link which would call the controller action. This is assuming that the action method returns a FileStreamResult and sets the correct content type so that the browser interprets the result and renders it accordingly.
With your approach you'd have to interpret in the onSuccessHandler of the post on how to render the generated stream.

Categories