I'm using a framework called PartialJS that follows a MVC architecture to build a webApp that will verify a user's input and make a request to an API and render the API response.
I'm not sure how to redirect the user to the rendered page after verification and API call has finished. Where should the page redirect and API calls be made?
Here's a quick breakdown of what the user will see with 'bullet' marks denoting what happens in the backend:
User presented with a form and fills information
exports.onValidation() called via a serialized JSON to verify that
all fields completed accurately (triggered by a button), done without
a page refresh.
API call is made with user's information, will not return until response is received and parsed
Form rendered with decoded JSON response from external API
I have tried using this in the 'view.html' page but the page redirects before verification.
<buttononclick="window.location='http://www.CaliCoder.com/results';">Submit</button>
<script type="text/javascript">
$(document).ready(function() {
$('button').bind('click', function() {
$.post('/', $('#f').serialize(), function(d) {
var err = $('#error');
if (d instanceof Array) {
err.empty();
d.forEach(function(o) {
err.append('<div>' + o.error + '</div>');
});
err.show();
return;
};
$('#f').trigger('reset');
err.empty();
err.show().html('SUCCESS! Please wait while the request is being made')
});
});
});
</script>
Here's what happens in the 'controller.js' end of things.
function json_form() {
var self = this;
var error = self.validate(self.post, ['intersection', 'hours', 'minutes', 'phone'])
if (error.hasError()) {
self.json(error);
return;
}
// save to database
var db = self.database('forms');
db.insert(self.post);
self.json({ r: true });
}
function get_routes(hours, minutes, intersection) {
//The following code makes a call that returns an array with data to be rendered by another view controller.
var stops = this.module('cumtd').GetStopsBySearch('springfied busey');
}
Thanks for reading! Sorry for sounding confusing, I'm new to JS and Node programming. :(
You have problem in clide-side JavaScript, solution:
HTML:
<button>Submit</button>
JavaScript:
$(document).ready(function() {
$('button').bind('click', function() {
$.post('/', $('#f').serialize(), function(d) {
var err = $('#error');
if (d instanceof Array) {
err.empty();
d.forEach(function(o) {
err.append('<div>' + o.error + '</div>');
});
err.show();
return;
};
$('#f').trigger('reset');
err.empty();
err.show().html('SUCCESS! Please wait while the request is being made');
// HERE REDIRECT:
setTimeout(function() {
window.location.href = 'http://www.CaliCoder.com/results';
}, 3000);
});
});
});
Related
How can I go about adding the value of an input box into an array and then display the contents of that array?
This is what I've come up with and I'm not sure why it's not working - the console.log doesn't post anything to the console, either.
var user = user;
if (!user) {
user = prompt('Please choose a username:');
if (!user) {
alert('Your name has been set to "Anonymous"');
} else {
alert('Your name has been set to "'+ user +'"');
}
}
var items = [];
function userArray() {
items.push(user);
return false;
console.log(items);
}
socket.on('onlineUsers', function (data) {
$('.dispUser').html(items);
});
The rest of the code in the file is below, just in case it helps... (changed the return statement, as per the first answer)
var user = user;
if (!user) {
user = prompt('Please choose a username:');
if (!user) {
alert('Your name has been set to "Anonymous"');
} else {
alert('Your name has been set to "'+ user +'"');
}
}
var items = [];
function userArray() {
items.push(users);
console.log(items);
return false;
}
socket.on('onlineUsers', function (data) {
$('.dispUser').html(items);
});
//Counts the number of users online
socket.on('count', function (data) {
$('.user-count').html(data);
});
//Receives messages and outputs it to the chat section
socket.on('message', function (data) {
$('.chat').append('<p><strong>' + data.user + '</strong>: ' + data.message + '</p>');
$('.chat').scrollTop($('.chat').height());
});
//SENDING OF THE MESSAGE
//Submit the form through HTTPS
$('form').submit(function (e) {
e.preventDefault();
// Retrieve the message from the user
var message = $(e.target).find('input').val();
// Send the message to the server
socket.emit('message', {
user: user || 'Anonymous',
message: message
});
// Clears the message box after the message has been sent
e.target.reset();
$(e.target).find('input').focus();
});
Answer
Your implementation is fine, but you have a bug which is preventing it from working as you've described.
The call to console.log(items) does not print anything, because that line of code never runs.
When you return from a function, the subsequent lines of code will not be ran. You should return as the last line within your function, or wrap it in a conditional.
For example:
function userArray() {
items.push(user);
console.log(items);
return false;
}
How to debug
Learning the techniques to figure this issue out yourself is an invaluable tool. You can leverage a debugger, such as the Chrome Devtools, to add breakpoints to your code. These will allow you to stop execution on a particular line, view the value of variables, and step through the remaining lines of code.
Doing so would make it clearly visible that the line of code is never running.
Find more details here: https://developers.google.com/web/tools/chrome-devtools/javascript
I would like to test if the ajax request is identical so it can be aborted or some other alert action taken?
In reality clients can change the request via a few form elements then hit the refresh button.
I have made a poor attempt at catching the identical request. Need to keep the timer refresh functionality.
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
var current_request_id = 0;
var currentRequest = null;
var lastSuccessfulRequest = null;
function refreshTable() {
$('#select').html('Loading');
window.clearTimeout(timer);
//MY CATCH FOR DUPLICATE REQUEST NEEDS WORK
if (lastSuccessfulRequest == currentRequest)
{
//currentRequest.abort();
alert('Duplicate query submitted. Please update query before resubmission.');
}
var data = {
"hide_blanks": $("#hide_blanks").prop('checked'),
"hide_disabled": $("#hide_disabled").prop('checked'),
};
json_data = JSON.stringify(data);
current_request_id++;
currentRequest = $.ajax({
url: "/calendar_table",
method: "POST",
data: {'data': json_data},
request_id: current_request_id,
beforeSend : function(){
if(currentRequest != null) {
currentRequest.abort();
}
},
success: function(response) {
if (this.request_id == current_request_id) {
$("#job_table").html(response);
$("#error_panel").hide();
setFixedTableHeader();
}
},
error: function(xhr) {
if (this.request_id == current_request_id) {
$("#error_panel").show().html("Error " + xhr.status + ": " + xhr.statusText + "<br/>" + xhr.responseText.replace(/(?:\r\n|\r|\n)/g, "<br/>"));
}
},
complete: function(response) {
if (this.request_id == current_request_id) {
$("#select").html("Refresh");
window.clearTimeout(timer);
stopRefreshTable();
window.refreshTableTimer = window.setTimeout(refreshTable, 10000);
lastSuccessfulRequest = currentRequest;
}
}
});
}
//TIMER STUFF TO refreshTable()
//THIS SECTION WORKS FINE
var startDate = new Date();
var endDate = new Date();
var timer = new Date();
function startRefreshTable() {
if(!window.refreshTableTimer) {
window.refreshTableTimer = window.setTimeout(refreshTable, 0);
}
}
function stopRefreshTable() {
if(window.refreshTableTimer) {
self.clearTimeout(window.refreshTableTimer);
}
window.refreshTableTimer = null;
}
function resetActive(){
clearTimeout(activityTimeout);
activityTimeout = setTimeout(inActive, 300000);
startRefreshTable();
}
function inActive(){
stopRefreshTable();
}
var activityTimeout = setTimeout(inActive, 300000);
$(document).bind('mousemove click keypress', function(){resetActive()});
</script>
<input type="checkbox" name="hide_disabled" id="hide_disabled" onchange="refreshTable()">Hide disabled task<br>
<br><br>
<button id="select" type="button" onclick="refreshTable();">Refresh</button>
I'd use the power of .ajaxSend and .ajaxSuccess global handlers.
We'll use ajaxSuccess to store a cache and ajaxSend will try to read it first, if it succeeds it will trigger the success handler of the request immediately, and abort the request that is about to be done. Else it will let it be...
var ajax_cache = {};
function cache_key(settings){
//Produce a unique key from settings object;
return settings.url+'///'+JSON.encode(settings.data);
}
$(document).ajaxSuccess(function(event,xhr,settings,data){
ajax_cache[cache_key(settings)] = {data:data};
// Store other useful properties like current timestamp to be able to prune old cache maybe?
});
$(document.ajaxSend(function(event,xhr,settings){
if(ajax_cache[cache_key(settings)]){
//Add checks for cache age maybe?
//Add check for nocache setting to be able to override it?
xhr.abort();
settings.success(ajax_cache[cache_key(settings)].data);
}
});
What I've demonstrated here is a very naïve but functional approach to your problem. This has the benefit to make this work for every ajax calls you may have, without having to change them. You'd need to build up on this to consider failures, and to make sure that the abortion of the request from a cache hit is not getting dispatched to abort handlers.
One valid option here is to JSON.Stringify() the objects and compare the strings. If the objects are identical the resulting serialised strings should be identical.
There may be edge cases causing slight differences if you use an already JSONified string directly from the response so you'll have to double check by testing.
Additionally, if you're trying to figure out how to persist it across page loads use localStorage.setItem("lastSuccessfulRequest", lastSuccessfulRequest) and localStorage.getItem("lastSuccessfulRequest"). (If not, let me know and I'll remove this.)
I have the following scenario. Actual Page loading starts, user login is checked for authentication. If access granted, actual page loading completes and user can access the page. If access denied, actual page loading stops and user is redirected to 'access denied' page.
Infact the scenario should be like this. User authentication is checked. if access granted, actual page loading starts and user can access page. If access denied, user is directly directed to 'access denied' page.
can someone tell me how to include promise for this scenario. current code is as follows.
$q.when().then(function () {
return $rootScope.$emit('resetView', false, 'default');
}).then(function (result) {
loadNavBar(); //actual page loading starts here
}, function (error) {
$log.error("Caught an error:", error);
return $q.reject('New error');
});
the below function is loadNavBar() which gets executed. User authentication is done inside of this. Hence page loading starts and then user is checked. I want user to be checked first itself and then load page accordingly depending on his access rights.
var loadNavBar = function () {
//few functions here to display page.
//below code to check user authentication
var serviceURL_CheckUserExists = '/api/Pre/CheckUserExists';
//ajax to check if user exists in database. give/ deny access based on user present in DB and if user is set as blockuser in db.
$.ajax({
type: "GET",
url: serviceURL_CheckUserExists,
}).then(function (response) {
if (response.Results.length == 1 && response.Results[0].BlockUser == false) { //user has access if condition is satisfied.
$rootScope.myLayout.eventHub.emit('getUserName', response.Results[0].User_ID.trim());
$scope.role = "";
var details = response.Results[0];
for (var parameters in details) {
if (details[parameters] == true) {
$scope.role += parameters + ',';
}
}
$scope.role = $scope.role.replace(/.$/, ".");
var firstname = response.Results[0].FirstName;
firstname = firstname.replace(/\s/g, '');
$scope.$apply(function () {
$scope.username = response.Results[0].FirstName + " " + response.Results[0].LastName;
});
}
else { $window.location.href = '../../../BlockUser.html'; } //block access to actual page and redirect to 'access denied' page.
}
}
});
};
i think that the right approach to your problem is to use resolve property in the route, so the user can't navigate to certain pages if he isn't logged in and once he logged in you can inject the user object to the controller
for example to navigate to home page you must be logged in
.when("/home", {
templateUrl: "homeView.html",
controller: "homeController",
resolve: {
user: function(AuthenticationService){
return AuthenticationService.getUser();
}
}
})
app.controller("homeController", function ($scope, user) {
$scope.user = user;
});
https://www.sitepoint.com/implementing-authentication-angular-applications/
Here's a quick example of hiding the content until the user is authenticated to see it. Click the 'authenticate' button to trigger the function that you would run if the user is authenticated by your ajax call. Showing the content can be done with a fuction like:
function userIsAuthenticated(){
document.getElementById('pageContent').style.display = 'block';
}
See JsFiddle for a simple implementation.
My DiaryHub.vb has the following:
Imports Microsoft.AspNet.SignalR
Imports Microsoft.AspNet.SignalR.Hubs
Namespace UIS
<HubName("DiaryHub")>
Public Class DiaryHub
Inherits Hub
Public Sub PostDiaryHeadline()
' Call the addNewMessageToPage method to update clients.
Clients.All.addNewDiaryHeadlineToPage()
End Sub
End Class
End Namespace
My Home/Index window has the following code to initiate/configure SignalR.
$(function () {
// Save the reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// Invoke the function to be called back from the server
// when changes are detected
// Create a function that the hub can call back to display new diary Headline entry.
dHub.client.addNewDiaryHeadlineToPage = function () {
// refresh the Headline Entries to the page.
outputHLDiaryEntries();
};
// Start the SignalR client-side listener
$.connection.hub.start().done(function () {
// Do here any initialization work you may need
outputHLDiaryEntries();
});
})
The code works and on launch the Headline diary entries are displayed.
I also have a button that opens a Kendo window as a modal with a form for adding new diary entries using this function:
function openAddWindow() {
var addWindow = $("#window").data("kendoWindow");
addWindow.refresh({
url: "Home/AddDiaryEntry/"
});
addWindow.open();
addWindow.center();
}
I then have the following Javascript in my AddDiaryEntry page:
function createDiaryEntry() {
var validFlag = true;
var errorMsg = "";
//Validate New Diary Entry
// removed for brevity...
if (validFlag) {
//data is valid
//get value of checkbox
var cbValue = ($("#addNew_dHeadline").is(':checked')) ? true : false;
//clear error area
$('#errorArea').html("");
var response = ''
$.ajax({
url: 'Home/SaveDiaryEntry',
type: 'POST',
data: {
dDate: $("#addNew_dDate").text(),
dCreatedBy: $("#addNew_dCreatedBy").text(),
dName: '#AppShort',
dTeam: teamValue.value(),
dType: typeValue.value(),
dRef: $("#addNew_dREF").val(),
dHeadline: cbValue,
dServer: multiSelect.value(),
dComment: editor.value()
},
success: function (result) {
response = result;
alert(response);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
response = "err--" + XMLHttpRequest.status + " -- " + XMLHttpRequest.statusText + " -- " + errorThrown;
alert(response);
}
});
//close window
var addWindow = $("#window").data("kendoWindow");
addWindow.close();
//if headline entry call SignalR post function to refresh diary entries
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// function to update all clients
dHub.client.PostDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
} else {
//error in data
var out = '<ul class="error">' + errorMsg + '</ul>';
// display errors
$('#errorArea').html(out);
}
}
The code works fine - validates the data, saves data to database. The issue I'm having is when I try to call dHub.client.PostDiaryHeadline() to invoke the SignalR function. I get the error: JavaScript runtime error: Object doesn't support property or method 'PostDiaryHeadline'
How do I call the function? Should I call the function before I close the modal window?
From what I can see your actually expecting a response rather than a server call.
adding server will fire a request.
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.DiaryHub;
// function to update all clients
dHub.server.PostDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
Your already receiving the response here:
dHub.client.addNewDiaryHeadlineToPage = function () {
// refresh the Headline Entries to the page.
outputHLDiaryEntries();
};
//EDIT
There seems to be slight issues through out, so apart from the above(which needs fixing).
On the hub name (backend) replace with: <HubName("diaryHub")>
In your JS replace with: var dHub = $.connection.diaryHub;
Finally in your createDiaryEntry(); body should look like so:
$.connection.hub.start().done(function () {
// Do here any initialization work you may need
if (cbValue) {
// reference to the SignalR hub
var dHub = $.connection.diaryHub;
// function to update all clients
dHub.server.postDiaryHeadline(); //THIS IS A FUNCTION IN DiaryHub.vb
}
});
There are a few SignalR issues but that should get you on the right path.
Most SignalR issues stem from case sensitivity and structuring. All very common.
Should be the last issue, replace with: dHub.server.postDiaryHeadline();
lower case "p"
I have a registration form, and when the user clicks the submit button the value in every textbox will be sent to server to insert that data, and return true/false.
Client:
Template.cust_register.events({
'click button': function(){
var email = $('#tbxCustEmail').val();
var msg = $('#tbxCustMsg').val();
var isSuccess = insertMsg(email,msg);
if(isSuccess){
alert("Success");
}else alert("Try again");
}
});
Server:
function insertMsg(email,msg){
Messages.insert({Email:email,Message:msg});
return true;
}
This turned out to not work.
How to solve this?
Many people said "use publish/subscribe", but I don't understand how to use that.
First, watch the introductory screencast and read the Data and security section of the docs.
Your code in a publish/subscribe model would look like this:
Common:
Messages = new Meteor.Collection('messages');
Client:
Meteor.subscribe("messages");
Template.cust_register.events({
'click button': function(){
var email = $('#tbxCustEmail').val();
var msg = $('#tbxCustMsg').val();
Messages.insert({Email:email,Message:msg});
}
});
Server:
Meteor.publish("messages", function() {
return Messages.find();
});
An alternative solution is to use Meteor.call('yourMethodName') (on the client).
Then, on the server, you can have
Meteor.methods({
yourMethodName: function() { /* validate input + return some data */ }
});
You can consider setting a session variable to the return value.
Meteor.call('yourMethodName', function (err, data) {
if (!err) {
Session.set('myData', data);
}
});
And then in some some template...
Template.whatever.helpers({
messages: function() {
return Session.get('myData');
}
});
Why do all this?
1) You can explicitly deny all direct `insert/update/find` queries from the client, and force usage of pre-defined Meteor methods.
2) You can manually determine when certain data is "refreshed".
Obviously, this methodology undermines the value of the subscription/publication model, and it should only be used in cases where real-time data isn't required.