I am using ServiceNow. I need to validate a form onSubmit. I am using GlideAjax with a script include to validate data. How can I pass variables from the Ajax function calendarDate(response) to other functions within the Client Script? When the glide ajax function returns an error message, I want to set the variable "isValid" to false.
I have done this easily with Client Scripts that do not involve GlideAjax. I simply set the variable isValid to the result of the function such as var isValid = checkLnrDates();
However, setting a variable equal to the function call when using GlideAjax does not return any value that I can use. I perhaps am not understanding the way that the GlideAjax functions are called and handled.
Catalog Client Script onSubmit
function onSubmit () {
var isValid = checkLnrDates();
if (isValid == false) {
g_form.submitted = false;
return false;
}
}
function checkLnrDates() {
var start = g_form.getValue('start_date');
//Check calendar date format valid YYYY-MM-DD
//Script include ClientDateTimeUtils checks the input data
var ajaxCalendarDate = new GlideAjax('ClientDateTimeUtils');
ajaxCalendarDate.addParam('sysparm_name', 'validateCalendarDate');
ajaxCalendarDate.addParam('sysparm_userDate', start);
ajaxCalendarDate.getXML(calendarDate);
}
function calendarDate(response){
//This is where we get the response returned from the ClientDateTimeUtils script include ajax function
var answer = response.responseXML.documentElement.getAttribute("answer");
if (answer != 'true'){
g_form.showFieldMsg('start_date', answer,'error');
//How can I pass the value of a variable to the function above? I want to set isValid to false
isValid = false;
return false;
}
}
The fact that you need to get a response from the AJAX round-trip before you can proceed means that you're not actually asynchronous. You could probably just call ajaxCalendarDate.getXMLWait() and then call ajaxCalendarDate.getAnswer() to get the response synchronously (see Synchronous GlideAjax)
However, since you're already submitting, and your code relies on a server-side function call to validate some input, you might just consider moving this logic into a Before Insert Business Rule that validates, and aborts using current.setAbortAction(true) if your validation fails.
Wiki example here.
Your business rule would look something like:
function onBefore(current, previous) {
if (!CliendDateTimeUtils.validateCalendarDate(current.start_date)) {
current.setAbortAction(true); // Don't save the record
gs.addErrorMessage("Start date is not valid"); // Add an error message for the user
}
}
try this:
function onSubmit(){
checkLnrDates();
return false;
}
function checkLnrDates() {
var start = g_form.getValue('start_date');
//Check calendar date format valid YYYY-MM-DD
//Script include ClientDateTimeUtils checks the input data
var ajaxCalendarDate = new GlideAjax('ClientDateTimeUtils');
ajaxCalendarDate.addParam('sysparm_name', 'validateCalendarDate');
ajaxCalendarDate.addParam('sysparm_userDate', start);
ajaxCalendarDate.getXML(calendarDate);
}
function calendarDate(response){
//This is where we get the response returned from the ClientDateTimeUtils script include ajax function
var answer = response.responseXML.documentElement.getAttribute("answer");
if (answer != 'true'){
g_form.showFieldMsg('start_date', answer,'error');
return false;
}
else
g_form.submit();
}
Related
I'm using API Jira
I'm doing some functions but before to use function, I need to verified if a value exist or not
If he exists so I can launch functions else do nothing.
I'm doing this :
// Call the file functions.js
var functions = require('./functions.js')
/*
Function getAllIssueForSCII displays all the issues in the form of a JSON and that browses all the keys that are in the SCII project
Function pushInitialization initializes the computer score card to 80 on Jira
*/
functions.getAllIssueForSCII().then(function(json){
for (let i=0; i<json.issues.length;i++){
if(json.issues[i].fields.customfield_14038 = null){ // i'm doing this
console.log(json.issues[i].key);
functions.pushInitialization(json.issues[i].key);
}
}
});
/*
A delay is added so that Jira can correctly recover the value 80.
Thanks to this value, we can do all the calculation (Function calculate)
Function pushComputerScoreCard push the final value into the computer score card.
Function generateJSON generates a JSON.
Function replaceCharacter solve the problem of array inside the JSON
*/
setTimeout(function() {
functions.getAllIssueForSCII().then(function(json){
for (let i=0; i<json.issues.length;i++){
functions.calculate(json.issues[i]);
functions.pushComputerScoreCard(json.issues[i].key);
functions.generateJSON(json.issues[i].key);
functions.replaceCharacter();
}
});
}, 1000)
My problem: After the settimeout, he recover value already exist and do the calcul...
I need to verified my condition in all of the script .
Thanks for your help
You are assigning null value in an if condition:
if(json.issues[i].fields.customfield_14038 = null){ // i'm doing this
You need to compare values:
if(json.issues[i].fields.customfield_14038 === null){ // You need to do this:
So this is my code
"use strict";
alert("WORKING");
var tableName = "EmployeeCred";
// Add an event listener to call our initialization routine when the host is ready
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
alert("DeviceOnready WORKING");
$('#add-item').submit(authenticateLogin);
}
function authenticateLogin() {
alert("AUTENTHICATE WORKING");
var row, numItemsRead;
var user = document.getElementById('usernameInput').value
var pass = document.getElementById('passwordInput').value
alert("Username submitted "+user);
alert("Password submitted " + pass);
alert("creating server database connection");
var client = new WindowsAzure.MobileServiceClient('https://strivedatabaseapp.azurewebsites.net'); // define the client
alert("connection finished");
var table = client.getTable(tableName);
alert("reading table soon");
My intention is to try to cycle through a database until I find a value that matches both the username/password value taken from the input loginscreen. I understand that I assigned the whole database table into the variable table, but I don't know quite how to cycle through the code. I tried multiple ways but I can't seem to figure it out. I believe I would have to do a table.read().then() but I can't seem to make it work. Any help? Please and thank you!
My end goal is to do something this
if (userInput == userDatabase || passInput == passDatabase) {
alert("You did it! You logged in!");
//code which passes user to next page
}
I assume that you want to filter data on the server.You could get the answer from this document.
You can use a where clause on the table reference:
table
.where({ userId: user.userId, complete: false })
.read()
.then(success, failure);
You can also use a function that filters the object. In this case, the this variable is assigned to the current object being filtered. The following code is functionally equivalent to the prior example:
function filterByUserId(currentUserId) {
return this.userId === currentUserId && this.complete === false;
}
table
.where(filterByUserId, user.userId)
.read()
.then(success, failure);
I have a javascript file that reads the input from textbox inputs in MVC/AngularJS. The method looks like the following:
$scope.Clients_CW = {
....
}
function sendForm(data)
{
$scope.Clients_CW = data;
var submitData = registrationService.SaveFormData($scope.Clients_CW);}
I'm using the jQuery wizard with next, previous and finish buttons. This is in a different javascript file to the code above. My finish button looks like the following:
$($this.buttons.finish).click(function() {
if(!$(this).hasClass('buttonDisabled')){
if ($.isFunction($this.options.onFinish))
{
var context = { fromStep: $this.curStepIdx + 1 };
if (!$this.options.onFinish.call(this, $($this.steps), context))
{
return false;
}
}
else {
var frm = $this.target.parents('form');
if (frm && frm.length)
{
alert($scope.Clients_CW);
frm.submit();
}
}
}
return false;
});
My question and problem is... how do I pass through the $scope.Clients_CW data to the finish button method or how do I call the sendForm(data) method and it's parameter in the finish button method?
You can very well use route params to pass data between states. Refer ngRoute. You could also store the data in $rootScope or $localStorage for example to use the data in multiple states. The latter step would also work if both the files are required for the same state.
After the user validate an order, the status of the order is set so validated and it is sent to another system X, the problem is that the plugin is fired twiced in some cases even more than twice and that lead to sending this entity multiple time to the system X. I tried to correct that by using the context.depth, but all the time is equal to 1.
JS Method:
Validate: function () {
Xrm.Page.getAttribute("eoz_validated").setValue(true);
Xrm.Page.data.entity.save();
ABE.Order.HideVisibleField();
Xrm.Page.ui.clearFormNotification('ProductError');
}
}
Plugin Execute method:
protected void ExecutePostOrderUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
if (localContext.PluginExecutionContext.Depth > 1)
{
return;
}
tracingService = localContext.TracingService;
var order = (Entity)localContext.PluginExecutionContext.InputParameters["Target"];
bool isValidated = order.GetAttributeValue<OptionSetValue>("abe_isValidated").Value : false;
if (isValidated )
{
SendToSystemX(localContext.OrganizationService, order.Id);
SendProductsToOwner(localContext.OrganizationService, order.Id);
}
var statecode = order.Contains("statecode") ? order.GetAttributeValue<OptionSetValue>("statecode").Value : -1;
}
If your plugin is registered to trigger on update of "eoz_validated" and also updates "eoz_validated" then you can have an infinite execution loop.
To avoid this, before updating your context entity, reinstantiate it:
var updatedEntity = new Entity { LogicalName = context.LogicalName, Id = context.Id };
This removes all attributes that would otherwise have been updated such as "eoz_validated" which is contained within the context entity. Note that in your code you store the context entity within a variable called order.
I'm just guessing here (and don't have 50 reputation to ask a question). If this is happening in your code then presumably it's within SendToSystemX(IOrganizationService, Guid) or SendProductsToOwner(IOrganizationService, Guid).
I'm trying to use Javascript in an OO style, and one method needs to make a remote call to get some data so a webpage can work with it. I've created a Javascript class to encapsulate the data retrieval so I can re-use the logic elsewhere, like so:
AddressRetriever = function() {
AddressRetriever.prototype.find = function(zip) {
var addressList = [];
$.ajax({
/* setup stuff */
success: function(response) {
var data = $.parseJSON(response.value);
for (var i = 0; i < data.length; i++) {
var city = data[i].City; // "City" column of DataTable
var state = data[i].State; // "State" column of DataTable
var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
addressList.push(address);
}
}
});
return addressList;
}
}
The webpage itself calls this like follows:
$('#txtZip').blur(function() {
var retriever = new AddressRetriever();
var addresses = retriever.find($(this).val());
if (addresses.length > 0) {
$('#txtCity').val(addresses[0].getCity());
$('#txtState').val(addresses[0].getState());
}
});
The problem is that sometimes addresses is inexplicably empty (i.e. length = 0). In Firebug the XHR tab shows a response coming back with the expected data, and if I set an alert inside of the success method the length is correct, but outside of that method when I try to return the value, it's sometimes (but not always) empty and my textbox doesn't get populated. Sometimes it shows up as empty but the textbox gets populated properly anyways.
I know I could do this by getting rid of the separate class and stuffing the whole ajax call into the event handler, but I'm looking for a way to do this correctly so the function can be reused if necessary. Any thoughts?
In a nutshell, you can't do it the way you're trying to do it with asynchronous ajax calls.
Ajax methods usually run asynchronous. Therefore, when the ajax function call itself returns (where you have return addressList in your code), the actual ajax networking has not yet completed and the results are not yet known.
Instead, you need to rework how the flow of your code works and deal with the results of the ajax call ONLY in the success handler or in functions you call from the success handler. Only when the success handler is called has the ajax networking completed and provided a result.
In a nutshell, you can't do normal procedural programming when using asynchronous ajax calls. You have to change the way your code is structured and flows. It does complicate things, but the user experience benefits to using asynchronous ajax calls are huge (the browser doesn't lock up during a networking operation).
Here's how you could restructure your code while still keeping the AddressRetriever.find() method fairly generic using a callback function:
AddressRetriever = function() {
AddressRetriever.prototype.find = function(zip, callback) {
$.ajax({
/* setup stuff */
success: function(response) {
var addressList = [];
var data = $.parseJSON(response.value);
for (var i = 0; i < data.length; i++) {
var city = data[i].City; // "City" column of DataTable
var state = data[i].State; // "State" column of DataTable
var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
addressList.push(address);
}
callback(addressList);
}
});
}
}
$('#txtZip').blur(function() {
var retriever = new AddressRetriever();
retriever.find($(this).val(), function(addresses) {
if (addresses.length > 0) {
$('#txtCity').val(addresses[0].getCity());
$('#txtState').val(addresses[0].getState());
}
});
});
AddressRetriever = function() {
AddressRetriever.prototype.find = function(zip) {
var addressList = [];
$.ajax({
/* setup stuff */
success: function(response) {
var data = $.parseJSON(response.value);
for (var i = 0; i < data.length; i++) {
var city = data[i].City; // "City" column of DataTable
var state = data[i].State; // "State" column of DataTable
var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
addressList.push(address);
processAddresss(addressList);
}
}
});
}
}
function processAddresss(addressList){
if (addresses.length > 0) {
$('#txtCity').val(addresses[0].getCity());
$('#txtState').val(addresses[0].getState());
}
}
or if you want don't want to make another function call, make the ajax call synchronous. Right now, it is returning the array before the data is pushed into the array
Not inexplicable at all, the list won't be filled until an indeterminate amount of time in the future.
The canonical approach is to do the work in your success handler, perhaps by passing in your own callback. You may also use jQuery's .when.
AJAX calls are asynchroneous, which means they don't run with the regular flow of the program. When you execute
if (addresses.length > 0) {
addresses is in fact, empty, as the program did not wait for the AJAX call to complete.