I'm failry new to Javascript and Servicenow so bear with me please. I'm creating a fix script to populate the incident breach time label on the incident task. It will show the same SLA as the parent incident. My below script returns the correct number of records that should be updated. However, when I go to update the record in my second GlideRecord, it only updates one record(Should be about 125). I commented the update portion of the code for testing purposes. Any suggestions? Thanks
var grSLA = new GlideRecord('u_incident_task');
grSLA.addEncodedQuery('u_incident_breach_timeISEMPTY^parentISNOTEMPTY^stateIN1,2,4');
grSLA.query();
var count=0;
gs.info("{0} of Itasks found to update", grSLA.getRowCount());
while (grSLA.next())
{
var ipar = grSLA.parent.sys_id;
}
gs.print(ipar);
var grName = new GlideRecord('task_sla');
grName.addQuery('task', ipar);
grName.addQuery('stage', 'in_progress');
grName.query();
while (grName.next())
{
var bTime = grName.planned_end_time.getDisplayValue();
grSLA.u_incident_breach_time=bTime; //sets the Incident Breach Time on the iTask
//grSLA.update();
count++;
}
I believe you need to move your task_sla loop inside of your u_incident_task loop.
It is only updating the final one since ipar is the last record in the loop.
var grSLA = new GlideRecord('u_incident_task');
grSLA.addEncodedQuery('u_incident_breach_timeISEMPTY^parentISNOTEMPTY^stateIN1,2,4');
grSLA.query();
var count=0;
gs.info("{0} of Itasks found to update", grSLA.getRowCount());
while (grSLA.next())
{
var ipar = grSLA.parent.sys_id;
gs.print(ipar);
var grName = new GlideRecord('task_sla');
grName.addQuery('task', ipar);
grName.addQuery('stage', 'in_progress');
grName.query();
while (grName.next())
{
var bTime = grName.planned_end_time.getDisplayValue();
grSLA.u_incident_breach_time=bTime; //sets the Incident Breach Time on the iTask
grSLA.update();
count++;
}
}
Related
A project includes a page on which exists a column showing foods associated with a meal and a (paginated) column of foods not associated with a meal. A script allows to click on a food in the paginated column, have that food removed from the list of available foods and appear in the list of associated foods. In the dev environment I can demonstrate that the script works.
In an effort to learn how to use Panther in testing I've tried to reproduce the effect of clicking on a food. The test code below hopes to show that the first row of the table of unassociated foods changes after a click. That test runs without error but fails. The question, then, is how or whether to make a test that shows a change in the table.
Edit: When I forced a Firefox client (static::createPantherClient(['browser' => static::FIREFOX]);) and adding PANTHER_NO_HEADLESS=trueto.env.test.local` the test ran slow enough for me to observe the first table row was removed. So somehow the test needs a way to read the new first row (and is different from how the test tries to do that now).
Edit 2: If I insert the lines $client->request('GET', 'http://diet/meal');$newCrawler = $client->clickLink('edit'); after executing the script I can get the test to pass. This seems to be a different test from expecting the test to pass without leaving and returning to the page. Or is it not possible to test without leaving?
Edit 3: Since Panther says it "can wait for asynchronously loaded elements to show up" I added a data attribute which increments on clicking. The test now includes the line $this->assertSelectorWillNotContain("document.querySelector('#mealid').getAttribute('data-rte')", $rteCount);. Nice, except that Panther returns Given css selector expression "document.querySelector('#mealid').getAttribute('data-rte')" is invalid even though a Firefox console with the identical selector returns an integer.
table row: <td data-foodid="185">dolor</td>
test code:
class MealTest extends PantherTestCase
{
public function testFood()
{
$client = static::createPantherClient();
$client->followRedirects();
$client->request('GET', 'http://diet/meal');
$this->assertPageTitleContains('Meals');
$crawler = $client->clickLink('edit');
$this->assertPageTitleContains('Edit Meal');
$foodLink = $crawler->filter('#meal_pantry td')->first();
$q = $foodLink->attr('data-foodid');
$client->executeScript("document.querySelector('#meal_pantry td').click()");
$client->waitFor('#meal_pantry');
$nextUp = $crawler->filter('#meal_pantry td')->first();
$p = $nextUp->attr('data-foodid');
$this->assertNotEquals($p, $q);
}
}
javascript:
$('td').on('click', function (e) {
var foodId = $(e.currentTarget).data('foodid');
var mealId = $("#mealid").data("mealid");
var tableId = $(this).parents('table').attr('id');
var pageLimit = $("#mealid").data("pagelimit");
$packet = JSON.stringify([foodId, mealId, tableId]);
$.post('http://diet/meal/' + mealId + '/editMealFood', $packet, function (response) {
editFoods = $.parseJSON(response);
var readyToEat = $.parseJSON(editFoods[0]);
var pantry = $.parseJSON(editFoods[1]);
var table = document.getElementById('ready_foods');
$('#ready_foods tr:not(:first)').remove();
$.each(readyToEat, function (key, food) {
row = table.insertRow(-1);
cell = row.insertCell(0);
cell.innerHTML = food;
});
var table = document.getElementById('meal_pantry');
$('#meal_pantry tr:not(:first)').remove();
$('li.active').removeClass('active');
$('li.page-item:nth-of-type(2)').addClass('active');
$.each(pantry.slice(0, pageLimit), function (key, array) {
food = array.split(",");
foodId = food[0];
foodName = food[1];
var row = table.insertRow(-1);
var cell = row.insertCell(0);
cell.innerHTML = foodName;
cell.setAttribute('data-foodid', foodId);
});
location.reload();
});
});
Turns out I've been using the wrong assertions. The eventual solution:
$client = static::createPantherClient();
$client->followRedirects();
$client->request('GET', 'http://diet/meal');
$this->assertPageTitleContains('Meals');
$crawler = $client->clickLink('edit');
$this->assertPageTitleContains('Edit Meal');
$rteCount = $crawler->filter('#mealid')->attr('data-rte');
$client->executeScript("document.querySelector('#meal_pantry td').click()");
$client->waitForAttributeToContain('#mealid', 'data-rte', $rteCount + 1);
im trying to change the href of my var explanation 11 based on the conditions obtained.
here's the code for the variable
if ( savings_budget_aycs > totalexp ) {
var msg="UNDER";
var explanation="You still have some excess money after factoring all your expenses in your budget. You may want to start looking at investing your excess money or increasing your savings. Do read out content on";
var explanation11=" saving and investing";
var explanation12=" to understand more.";
var explanation2="Since you have more money to use from your budget, one option is to increase your savings.";
var remaining=savings_budget_aycs-totalexp;
} else {
var msg="OVER";
var remaining=totalexp-savings_budget_aycs;
var explanation="This means that your spending has exceeded your income. You will need to make some cutbacks to be able to stay within your budget. Do read our content on";
var explanation11=" planning and budgeting";
var explanation12=" to understand more.";
var explanation2="You are over budget, so try to see what you can cut down on to save some money.";
}
and here is where i call the explanation
firstTableHtml += "<div class=\'explanation\'>"+explanation+"<a id=\'link-saving\'>"+explanation11+"</a>"+explanation12+"</div>";
Remove back slashes before the quotes.
firstTableHtml += "<div class='explanation'>"+explanation+"<a id='link-saving'>"+explanation11+"</a>"+explanation12+"</div>";
I'm trying to condense two processes down in to one by having the two pages I need on one page using an iframe.
I have a page that contains a text area (used for sending an email) and then I have a purchase reference page that contains the details of someones purchase.
I'm trying to append an iframe of the purchase page to the bottom of my email page and then grab some data that's on it and insert it in to the text area.
EDIT: This is what I have so far:
Script one
//Grabs the selected purchase number
var purchaseNumber = window.getSelection();
purchaseNumber = purchaseNumber.toString();
var purchaseTitle;
var purchaseNumber;
function frameLoaded() {
purchaseTitle = window.frames['purchaseIframe'].contentDocument.getElementById ('listingTitle');
purchaseNumber = window.frames['purchaseIframe'].contentDocument.getElementById ('auctionSoldIdDisplay');
purchaseTitle = purchaseTitle.innerHTML;
purchaseNumber = purchaseNumber.innerHTML
var purchaseDetails = purchaseTitle + " - " + purchaseNumber;
insertText = insertText.replace("PURCHASEDETAILS", purchaseDetails);
}
if(purchaseNumber.length > 0){
var purchaseIframe = document.createElement('iframe');
purchaseIframe.src = 'http://www.mysite.co.nz/Admin/Listing/PurchaseDisplay.aspx?asid=' + purchaseNumber + '&submit1=++GO++';
purchaseIframe.setAttribute("height","1000");
purchaseIframe.setAttribute("width","100%");
purchaseIframe.setAttribute("id","purchaseIframe");
purchaseIframe.setAttribute("onload", "frameLoaded();");
void(document.body.appendChild(purchaseIframe));
alert(purchaseNumber);
}
Script Two
//Gather the selected template
var selectedTxt = document.getElementById('txtEmailText').value;
//Change the selected txt to a string
var insertText = selectedTxt.toString();
var purchaseTitle = window.frames['purchaseIframe'].contentDocument.getElementById ('listingTitle');
var purchaseNumber = window.frames['purchaseIframe'].contentDocument.getElementById ('auctionSoldIdDisplay');
purchaseTitle = purchaseTitle.innerHTML;
purchaseNumber = purchaseNumber.innerHTML
var purchaseDetails = purchaseTitle + " - " + purchaseNumber;
insertText = insertText.replace("PURCHASEDETAILS", purchaseDetails);
//Pasting the variable in to the textarea
document.getElementById('txtEmailText').value = insertText;
Effectively I am highlighting the purchase reference number on the page then executing this script to open the purchase page using the highlighted number. I am then grabbing the text values of the elements I need and pasting them in to the text area.
I'm still pretty new to javascript and am teaching myself as I go.
If i run the above scripts one after the other then it works like a charm, however if I try to run them together with the second in an onload() function set to the iframe then it won't.
Any help would be greatly appreciated or if you could point me in the direction of an article to help.
My first thought is that the iframe is not fully loaded before you try to get the values from it. My thought would be to try adding an onload event to your iframe and then when it loads invoke a function that grabs the value.
I would add purchaseIframe.setAttribute("onload", "frameLoaded();"); to your purchaseIframe block and then add the frameLoaded() function to your script. something like:
function frameLoaded() {
var purchaseTitle = window.frames[0].document.getElementById("listingTitle" );
var purchaseNumber = window.frames[0].document.getElementById("auctionSoldIdDisplay");
console.log(purchaseTitle.innerHTML);
console.log(purchaseNumber.innnerHTML);
}
And see if something like that grabs the right values. If it does than you can plug it in where you need it.
Am I understanding your problem correctly?
I am trying to add create an editable table in HTML. So, I need to add rows, when user clicks on a button. Here is the code I am using.
//remove all old rows.
while (summaryTableElement.firstChild) {
summaryTableElement.removeChild(summaryTableElement.firstChild);
}
//add a new text area in the summary field.
summaryTableElement.innerHTML = "<textarea id='summaryTextBox' value='' onblur='saveSummary()'> </textarea> ";
This code works fine on Chrome and Mozilla. But, IE doesn't allow editing innerHTML. This HTML will be displayed inside a VB form, so I have "browser" and "webbrowser" controls available. Both of those controls use IE engine, so this code does not work there.
I have tried using firstchild.innerHTML instead so that I am not editing table row directly, and even that gave me same error.
I tried using WebKitBrowser. But, that causes an exception on load. Apparently that control uses some old method, and the method is changed. So, that control is out of question too.
Now, I am confused as to how to solve this problem?
Edit:
I found the issue with WebKitBrowser. It was specific to x86, while my project was targeting both x64 and x86. Switching it to x86 for both, worked. Although, webkit browser do not take return key values. So, I have a new problem. Pressing enter does not create a new line in table cell, and instead passes the event to vb form.
Edit:
Okay, so I tried working further with WebKitBrowser. But, that control gives me accessviolatedexception. So, I am thinking about going back to using the default browser control, for now.
As for default control, I checked further. Apparently, code works fine in IE9 and above. But, vb.net control uses some weird JS engine. So, I am receiving error only in vb control.
Here is the complete code for reference:
var summaryChanges = "";
var isSummaryClickable = true;
//creates a textbox for editing purpose and include the original summary data.
function modifySummary(id) {
var summaryTableElement; //to get the table cells so that we can access the value
var originalSummary = ""; //to hold the original summary while we create a text box
var loopCounter = 0;
if (isSummaryClickable == true) {
isSummaryClickable = false; //saves event spilling when clicked on the newly created textbox
//get the summary table id saved.
summaryTableElement = document.getElementById (id).childNodes.item(0);
//add existing data to a string to save it for later.
for (loopCounter = 0; loopCounter < summaryTableElement.childNodes.length; loopCounter++) {
originalSummary = originalSummary + summaryTableElement.childNodes.item(loopCounter).childNodes.item(0).innerHTML + "\n";
}
//remove all old rows.
while (summaryTableElement.firstChild) {
summaryTableElement.removeChild(summaryTableElement.firstChild);
}
//add a new text area in the summary field.
summaryTableElement.innerHTML = "<tr><td><textarea id='summaryTextBox' value='' onblur='saveSummary()'> </textarea></td></tr> ";
//set the width of the textbox to allow easy modification
document.getElementById("summaryTextBox").style.width = '600px';
//add original summary text to the text area and set focus
document.getElementById("summaryTextBox").value = originalSummary;
document.getElementById("summaryTextBox").focus();
}
}
// saves the updated summary data back to HTML
function saveSummary()
{
var newHTML = "";
var changesSummary;
var changesSubString = new Array();
var index = 0;
var elementToUpdate;
//get the summary table id saved.
elementToUpdate = document.getElementById("SummaryData"); //.childNodes.item(0);
//get changes from the textbox
changesSummary = document.getElementById("summaryTextBox").value;
//generate string array for separate lines from summaryChanges
changesSubString = changesSummary.split("\n");
//generate new HTML string for the summary fields
//alert(changesSubString.length);
for (index = 0; index < changesSubString.length; index++) {
newHTML = newHTML + "<tr><td class='Text' style='padding-left: 4px;padding-bottom: 4px;' id='SummaryLine" + index + "'</td>" + changesSubString[index] + "</tr>"
}
//update the HTML to the element
elementToUpdate.innerHTML = newHTML;
//allow clicking on summary table
isSummaryClickable = true;
}
function doNothing(id) {
//empty function for future use
return;
}
//this function is called from vb.net script to read the js variable.
//do not change the function definition (name or parameters or return type)
//any change will cause error in vb.net script
function jsInvokedFunction() {
var updatedHTML; // to be used by vb.net invoked function to get updated body
var testVariable = "test";
updatedHTML = document.body.innerHTML.toString();
return updatedHTML.toString();
}
I receive an error at the start of the line summaryTableElement.innerHTML = " ";
It is possible I am missing some other error, but I couldn't find any.
I have created a button to escalate a case. I am trying to change the record type, the "Owner" and append "Case Escalated" to the "Notes" field.
Code:
{!REQUIRESCRIPT("/soap/ajax/27.0/connection.js")}
var objCase = new sforce.SObject('Case');
objCase.Id = '{!Case.Id}';
objCase.Owner__c = 'Global Salesforce Team';
objCase.RecordTypeId = '012C00000007l5WIAQ';
objCase.Notes__c += 'Case Escalated';
var result = sforce.connection.update([objCase]);
if(result[0].success=='true'){
alert('The Case was Updated Successfully');
location.reload(true);
} else if(result[0].success=='true'){
alert('There was an issue updating the case');
}
However this wipes the "Notes" field and adds in "undefinedCase Escalated" instead of appending the string "Case Escalated" to the end of whatever is in there.
I am new to javascript, please be nice :)
i saw the code and the problem seems to be that you are creating a new instance of the Case to update, so there is nothing on the field Notes, and once you insert the record it overwrites with the only text there, 'Case Escalated', to get this to work you have to do a query to look for the value that was before on the field and then append the value to the notes__c field.
{!REQUIRESCRIPT("/soap/ajax/27.0/connection.js")}
var result = sforce.connection.query("select Id, Owner__c, RecordTypeId, Notes__c from Case WHERE Id='{!Case.Id}' LIMIT 1");
var records = result.getArray('records');
var objCase = records[0];
objCase.Owner__c = 'Global Salesforce Team';
objCase.RecordTypeId = '012C00000007l5WIAQ';
objCase.Notes__c += 'Case Escalated';
var result = sforce.connection.update([objCase]);
if(result[0].success=='true'){
alert('The Case was Updated Successfully');
location.reload(true);
} else if(result[0].success=='true'){
alert('There was an issue updating the case');
}
The link to the developer guide with an example is at http://www.salesforce.com/us/developer/docs/ajax/apex_ajax.pdf
Havent tested it and there is some error handling to be done in my code, but it should work.