Can I use SignalR to trigger an AJAX request on all clients? - ajax

I have a DIV in a view that must be refreshed when some data changes on the server. I can't update it regularly using an interval. The data changes as a result of a user doing something in their client.
In other words: User A clicks a button, and data changes on the server. All users should "immediately" see the change as a DIV in their page gets refreshed.
How can it be done?

I think you can follow this tutorial to realize your feature. But you need to do some changes based on the code.
First, that tutorial provides a sample which looks like a chat room, that means some in his client hit the send button, then other clients will display the newly send message immediately. So I think it really fits your scenario. All codes are provided inside the tutorial page and I show the code where you need to change below.
First, you can change the ChatHub.cs file to add the logic about updating database.
public class ChatHub : Hub
{
public async Task SendMessageToAllAndUpdateData(string user, string message, string state)
{
//write some code to update the database here
await Clients.All.SendAsync("ReceiveMessage", user, message, state);
}
}
Then you need to modify the js file which now works like append an li element to the page, but you should change it to update the data displayed before.
connection.on("ReceiveMessage", function (user, message, state) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
li.textContent = `${user} says ${message} and his state is ${state}`;
//write code here to modify the data displayed in the page
document.getElementById("stateInput").value = state;
});

Related

How to refresh a BeanFieldGroup after a client request whitout a button?

i hope i will find help here.
Is it possible to refresh a single component in Vaadin.
For example do a client request which change a value [ type = String] inside a single component and refresh this component after it immediate.
Here the content for better understanding:
My Vars:
private static BeanFieldGroup<Service> binder = new BeanFieldGroup<Service>(Service.class);
private FormLayout form = new FormLayout();
My Constructor:
public ServiceDetails()
{
vl = new CssLayout();
vl.addComponent(new Label("Service Details"));
vl.addComponent(form);
vl.setStyleName("details");
vl.setSizeFull();
addPropertyChangeListener(new MyPropertyChangeListener());
refreshBT = new Button("Show Updated Content");
form.addComponent(refreshBT);
addListener();
form.addComponent(binder.buildAndBind("S-ID: ", "id"));
form.addComponent(binder.buildAndBind("Name: ", "name"));
form.addComponent(binder.buildAndBind("Description: ", "description"));
form.addComponent(binder.buildAndBind("Service Tags: ","allTagsOfService"));
form.addComponent(binder.buildAndBind("Attributes: ","allInOnAtt"));
form.addComponent(binder.buildAndBind("Capabilities: ","allInOnCapa"));
form.addComponent(binder.buildAndBind("Categorization: ","allInOnCat"));
form.addComponent(binder.buildAndBind("Relations: ","allInOnRela"));
form.addComponent(binder.buildAndBind("Stakeholder: ","allInOnStkh"));
form.addComponent(binder.buildAndBind("Resources: ","allInOnRes"));
form.addComponent(binder.buildAndBind("Quality: ","quality"));
form.addComponent(binder.buildAndBind("Process: ","process"));
form.addComponent(binder.buildAndBind("Finance: ","finance"));
form.setImmediate(true);
setCompositionRoot(vl);
}
The Button will update the shown content for the user. If a AJAX-request is done the data will be at the server but not shown. If the button is clicked the userview will be updated correctly.
Each variable change call a method which setup my content for the BeanFieldGroup.
public void setService(Service service)
{
setServ(service);
binder.setItemDataSource(getServ());
}
The Problem is now that i need to click this button for a userview refresh, if i clicked on the service inside a canvas structure. By the way this structure is realized in javascript, and a click will always do a AJAX-request [ type = POST] to the server. The send data will be saved correctly in a temporary variable but nothing will be shown at my page. The content change will not be shown to the user page. But this only appear if i use AJAX-requests. If i do click at another component it works without using the button. ):
Any idea how to fix this kind of problem.
Thx for each reply.
When working with http, you have to keep in mind, that the server usually can't inform the client about changes done on server side.
In vaadin, if you modify the UI on server side, outside of the normal "Action from client", then these changes will show up only on the next interaction with the client.
If you need to send the changes from the server to the client, you will have to use a push technology, where the server can inform the client about new/changed content.
Fortunally vaadin includes a easy to use implementation of this push system.
In the Book of Vaadin there is a complete section about server push.
Basically you add the #Push annotation to your UI class and add the required libraries.
You have to keep in mind, that you will need to synchronize access to the UI to get consistent results. (Also documented in the book of vaadin)

Back Button Clicked and Error Messages on Previous Page Still Display

I have a very simple 1 page form using ASP.NET MVC 3.
It has 3 inputs. If the user enters the correct inputs and the database retrieves a pdf, that pdf is displayed in the next page. I have used the PRG pattern, in so far as it is possible in this scenario:
public ActionResult Index()
{
SomeModel model = new SomeModel
{
... properties
};
return View(model);
}
[HttpPost]
public ActionResult Index(SomeModel model)
{
byte[] blob = someService.GoGetDetails(model);
TempData.Add("blobkey", blob);
return RedirectToAction("DisplayPdf");
}
public ActionResult DisplayPdf()
{
return File(TempData["blobkey"] as byte[], "application/pdf");
}
The problem use case is as follows.
User enters incorrect details and clicks Submit button. Red error text displays.
User then enters correct details and clicks Submit button. Pdf displays.
User THEN hits back button. Form displays with previous red error text visible.
A tester has made up a requirement that the red text should not be there when the back button is clicked.
Seems easy. Until you try. Does anyone have the magic bullet for this.
One thing I tried as a compromise did not work. That is, I tried to kill caching on the browser with this code inside the DisplayPdf acttion method:
this.ControllerContext.HttpContext.Response.Expires = 60;
this.ControllerContext.HttpContext.Response.ExpiresAbsolute = DateTime.Now.AddSeconds(-1);
this.ControllerContext.HttpContext.Response.AddHeader("pragma", "no-cache");
this.ControllerContext.HttpContext.Response.CacheControl = "no-cache";
It has no effect. Perhaps that works in the webforms world. Not here with the FileResult.
When back button is hit, there is no request to the server. It is all client-side. So, I do have access to javascript. But javascript has no access to the http headers, so there's no way of differentiating from where the page was loaded.
I'm keen to see if this has been solved before. My Googling came up empty.
Thanks
OK. I'm now satisfied. If :
Amazon.com
JsFiddle.net
Outlook.com
Dropbox.com
all exhibit the same behavour, then my work is not falling short of best practice.
Intercepting the navigation buttons of browsers seems very hacky to me. This is one use case where we have to make sure our code does no damage when users do dumb stuff. But resolve elegantly? Probably not a big driver when control is taken out of your hands by the browser.

View that hides/shows controls

I am in the process of porting a site I wrote from ASP.NET webforms to MVC3 and need some guidance as outlined below. I'm new to MVC3.
In my existing ASP.NET web forms project I have a simple page where the user enters a username, they then click a button which causes a postback, on postback there is some basic code that checks if the entered username exists in a user repository - if it does, a textbox containing the users e-mail is shown and the username textbox is made invisible. This happens with ajax and so when the username is entered, the textbox containing the e-mail along with an "Update" button is shown without a full page refresh.
I created a model such as:
public class ChangeEmailModel
{
[Required]
public string Username { get; set; }
[Required]
public string Email { get; set; }
}
Problem is that when the user first enters the page, they should only see a textbox prompting them to enter a username. Once the username is entered and an update button clicked, only then their e-mail is shown (retrieved from the database). Once the e-mail is shown, they can edit the e-mail and click update, which then will need to post to a controller action that saves the updated e-mail. I'm not yet fully used to thinking in the MVC way, so I'm not sure if I've started on the wrong foot with the model above...
Can someone give me some guidance on how this can be accomplished in MVC3 so I can give it a try?
I will start off by suggesting that you start using JQuery for your javascript/ajax functions. ASP.Net MVC3 supports JQuery nicely. I will ignore validation of the email for now as it will be much easier to get you started without it. A high level overview will be:
Add the JQuery script to your page
Add the JQuery vsdoc script to your page so you have some intellisense
Create a partial view to show the email and submit button
Create a controller action that performs the email lookup you mentioned
Create a div to accept the newly returned Email Update form
Use JQuery to override the submit on your username lookup to perform an ajax update instead (and populate the Email Update form div)
1. Add the JQuery script to your page
This should be pretty easy - just drag it from your scripts folder. I think mvc3 comes with jquery-1.5.1.js. Use the min (minified) version when you release to production.
2. Add the JQuery vsdoc script to your page so you have some intellisense
Not quite as easy here - you will want to use an if statement that always evaluates to false so the script is not actually included in your content. Having it on the page though, will cause VS to use it for intellisense. Put this near the top of your view:
#if (false) { <script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script> }
Hopefully you are using Razor. If not, start using it. It seemed a little foreign to me at first, but it requires much less markup.
3. Create a partial view to show the email and submit button
You could use the ViewBag to pass the Email address and UserName (for now as we are ignoring validation), but go ahead and make it strongly typed to your Model from above. Your view may look something like this:
#model ChangeEmailModel
#{using (Html.BeginForm("UpdateEmail", "Home", FormMethod.Post, new { id = "UpdateEmailForm" }))
{
<input type="hidden" name="userName" value="#Model.UserName" />
#Html.EditorFor(m => m.Email)
<button id="submitEmailUpdate" type="submit">Submit</button>
}
}
Note that we have given Ids to the form and the submit button. JQuery will find the form and button based on these ids. (if we need to, which we will if we want to "ajaxify" the action of updating the email. I did not go into that detail here, but it will be the same process to get that working as it is for the original username lookup)
4. Create a controller action that performs the email lookup you mentioned
I won't go into controllers much here (as you are asking about ajax type updates) but it might look like:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LookupEmail(string userName)
{
//connect to db and lookup email based on passed in username
//create a new instance of your model
var changeEmailModel = new ChangeEmailModel(.....)
//return a partial view
return PartialView("EmailUpdateForm", changeEmailModel);
}
Make sure to return a PartialView here rather than a View.
5. Create a div to accept the newly returned Email Update form
Make sure this div is not contained in your Username lookup form (as you want to hide it). We will be working with two separate forms. This div could be hidden if you prefer (but will start out empty anyway) I am calling it emailFormDiv
6. Use JQuery to override the submit on your username lookup to perform an ajax update instead
JQuery will allow you to attach functions to... well a lot of things, but we will be using it to override the submit button on your username lookup form. Assume that your original username lookup form with an id of "formUserNameLookup" that has a submit button with an id of "submitUserNameLookup". You would then create a script tag that looks something like this:
<script type="text/javascript" language="javascript">
$(document).ready(function () { //The document.ready function will fire when the html document is... ready
$('#submitUserNameLookup').click(function (ev) { //fires when the submit button is clicked
ev.preventDefault(); //prevent the normal action of the button click
$.post($('#formUserNameLookup').attr('action'), //get the url from the form's action attribute. Could be hard coded for simplicity
$('#formUserNameLookup').serialize(), //serialize the data in the form
function (response, status) {
$('#emailFormDiv').html(response); //replace the html of your div with the response
$('#formUserNameLookup').hide(); //hide the original form
}, 'html'); //states that we are expecting html back from the post
});
});
</script>
The code above is attaching a function to be run when the submit button is clicked. It won't run, of course, until the button is actually clicked. Using JQuery/Javascript to attach functions to html elements, rather than embedding them directly inside the element is definitely preferred, and is referred to as unobtrusive javascript. If you continue with ajaxifying more of your page, you will want to look into JQuery's live and/or delegate functions. Note that there are plenty of things that can be changed once you start looking toward performance and/or best practices. The above should get you going though. I hope I haven't made too many assumptions on your current level of familiarity with ASP.Net MVC (like controllers and posting to controllers) but by all means, ask if you need further help.

Google Chrome Extension - How can I include a content script more than once?

I've been working on Chrome Extension for a website for the past couple of days. It's coming along really nicely but I've encountered a problem that you might be able to help with.
Here's an outline of what the extension does (this functionality is complete):
A user can enter their username and password into the extensions popup - and verify their user account for the particular website
When a user browses http://twitter.com a content script is dynamically included that manipulates the DOM to include an extra button next to each tweet displayed.
When a user clicks this button they are presented with a dialog box
I've made a lot of progress but here is my problem:
When a user visits Twitter the content script is activated and all tweets on the page get my new button - but if the user then clicks 'More...' and dynamically loads the next 20 tweets... these new additions to the page DOM do not get affected by the content script (because it is already loaded).
I could add an event listener to the 'More...' button so it then triggers the original content script again (and adds the new button) but i would have to predict the length of twitter's ajax request response.
I can't tap into their Ajax request that pulls in more tweets and call my addCurateButton() function once the request is complete.
What do you think is the best solution? (if there is one)
What you want to do is to re-execute your content-script every time the DOM is changed. Luckily there is an event for that. Have a look at the mutation event called DOMNodeInserted.
Rewrite your content script so that it attaches an event listener to the body of the DOM for the DOMNodeInserted event. See the example below:
var isActive = false;
/* Your function that injects your buttons */
var inject = function() {
if (isActive) {
console.log('INFO: Injection already active');
return;
}
try {
isActive = true;
//inject your buttons here
//for the sake of the example I just put an alert here.
alert("Hello. The DOM just changed.");
} catch(e) {
console.error("ERROR: " + e.toString());
} finally {
isActive = false;
}
};
document.body.addEventListener("DOMNodeInserted", inject, false);
The last line will add the event listener. When a page loads the event is triggered quite often so you should define a boolean (e.g. var isActive), that you initialize to false. Whenever the inject function is run check whether isActive == true and then abort the injection to not execute it too often at the same time.
Interacting with Ajax is probably the hardest thing to coax a content script to do, but I think you’re on the right track. There are a couple different approaches I’ve taken to solving this problem. In your case, though, I think a combination of the two approaches (which I’ll explain last) would be best.
Attach event listeners to the DOM to detect relevant changes. This solution is what you’ve suggested and introduces the race condition.
Continuously inspect the DOM for changes from inside a loop (preferably one executed with setInterval). This solution would be effective, but relatively inefficient.
The best-of-both-worlds approach would be to initiate the inspection loop only after the more button is pressed. This solution would both avoid the timing issue and be efficient.
You can attach an event-handler on the button, or link that is used for fetching more results. Then attach a function to it such that whenever the button is clicked, your extension removes all the buttons from DOM and starts over inserting them, or check weather your button exists in that particular class of DOM element or not and attach a button if it doesn't.

Display a success message to user in a SharePoint Document Library after validation in ItemAdding Event

When validating a document in the ItemAdding event there are many ways to display errors to the user, but there doesn't seem to be a way to display successes to user, like a validation was successful. An info message to the user at the top of document library would be great.
public class MyItemEventReceiver : SPItemEventReceiver {
public MyItemEventReceiver() {}
public override void ItemAdding(SPItemEventProperties properties) {
// Do some validation
// If successful display message to user - can't seem to do
// If unsuccessful cancel and go to the error page - easy
}
}
}
In the event handler you have a Property called Cancel when set to true it will redirect you to the Error Page. Whereas when you dont distrub it, it will redirect you to the Metadata page of the document, i.e it will as you for the Name and Title of the document. Being said that out of the Box it is not possible to archive what you want to do. One alternate approach I would suggest is that once the validation is successful, set a Flag in the Session / Property Bag of the List with the Document GUID as the Key and in the Final Landing page deploy a Custom Web Part that will check for the this GUID and if there is a Value then It will display the Message.
Umm... edit List's AllItems.aspx or edit your masterpage, add Literal control to it. At ItemAdded event just refer to that control and set it's value.
Maybe it turns out you even need code-behind for that masterpage. Refer here.

Resources