I want to login with multiple logins for the domain in same browser.
example there is a messaging service call slack if i login in first tab and if i open second tab in same browser it should no share session with second tab it should be altogether a new one.
I've tried below block of code but it is not working how do i acheive this
var clearLocal = window.localStorage.clear.bind(window.localStorage);
var getLocal = window.localStorage.getItem.bind(window.localStorage);
var keyLocal = window.localStorage.key.bind(window.localStorage);
var removeLocal = window.localStorage.removeItem.bind(window.localStorage);
var setLocal = window.localStorage.setItem.bind(window.localStorage);
window.localStorage.getItem = function(key) {
alert("inside account key " + key);
var newKey = accountId + "::" + key;
alert("inside account new key " + newKey);
return getLocal(newKey);
}
window.localStorage.key = function(index) {
console.log("KEY " + index);
return keyLocal(index);
}
window.localStorage.removeItem = function(key) {
var newKey = accountId + "::" + key;
console.log("REMOVE " + newKey);
return removeLocal(newKey);
}
window.localStorage.setItem = function(key, value) {
var newKey = accountId + "::" + key;
alert("inside account new key " + newKey);
return setLocal(newKey, value);
}
Any suggestions more appreciated..
Related
I am working on angularjs 1.6.5
I am using following code to send data of invoice page.
$scope.products = [{qty: 0, description: ' ', sellingPrice: 0.0, unitPrice: 0.0, total: 0.0}];
$scope.fproducts = [];
$scope.generateInvoice = function () {
console.log("generateInvoice");
console.log($scope.fproducts);
console.log("sub total " + $scope.subTotal + " ft " + $scope.finalTotal + " pamt " + $scope.paidAmount + " baldue " + $scope.balancedue);
$scope.bd1 = {
'subTotal': $scope.subTotal,
'total': $scope.finalTotal,
'TotalPaid': $scope.paidAmount,
'invDateStr': $filter('date')($scope.invoiceDate, "MM/dd/yyyy"),
};
if ($scope.fproducts.length > 0) {
$scope.fproducts.forEach((total, index) => {
Object.entries(total).forEach(([key, value]) => {
console.log(index + " " + key + " " + value);
$scope.bd1[`billProductList[${index}].${key}`] = value;
});
});
}
//commenting above for each and removing comment from below code is
// working properly but I want to send dynamic data with above code
/* $scope.bd1[`billProductList[0].id`] = 1;
$scope.bd1[`billProductList[0].description`] = 1;
$scope.bd1[`billProductList[0].discountPercent`] = 150;
$scope.bd1[`billProductList[0].qty`] = 10;
$scope.bd1[`billProductList[0].sellingPrice`] = 100;
$scope.bd1[`billProductList[0].unitPrice`] = 100;
$scope.bd1[`billProductList[0].total`] = 150;*/
$scope.bd1[`BillPaidDetailses[0].paymentMode`] = $scope.paymentMode;
$scope.bd1[`BillPaidDetailses[0].amount`] = $scope.paidAmount;
console.log($scope.bd1);
$http({
method: 'POST',
url: 'added-invoice',
data: $httpParamSerializerJQLike($scope.bd1),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(function successCallback(data, status, headers, config) {
if (data.data.st === 1) {
$scope.success = true;
window.location = 'bhome#!/show-tax';
} else if (data.data.st === 0) {
$scope.success = false;
$scope.failure = true;
} else if (data.data.st === -1) {
$scope.success = false;
$scope.failure = true;
}
}, function errorCallback(data, status, header, config) {
$scope.success = false;
$scope.failure = true;
});
}
Above code is not passing value to server side object.
its console.log value is
on modifying above data
/*if ($scope.fproducts.length > 0) {
$scope.fproducts.forEach((total, index) => {
Object.entries(total).forEach(([key, value]) => {
console.log(index + " " + key + " " + value);
$scope.bd1[`billProductList[${index}].${key}`] = value;
});
});
}*/
$scope.bd1[`billProductList[0].id`] = 1;
$scope.bd1[`billProductList[0].description`] = 1;
$scope.bd1[`billProductList[0].discountPercent`] = 150;
$scope.bd1[`billProductList[0].qty`] = 10;
$scope.bd1[`billProductList[0].sellingPrice`] = 100;
$scope.bd1[`billProductList[0].unitPrice`] = 100;
$scope.bd1[`billProductList[0].total`] = 150;
as this is passing value to server object
its console.log is
I want to run my code using dynamic value specified in if condition.
What is the problem I am unable to get it.
EDIT I am using server side struts2
my code is
public class BillNewAction extends ActionSupport implements ModelDriven<BillDetails> {
BillDetails bd = new BillDetails();
private List<BillDetails> billList = new ArrayList<BillDetails>();
public String insert() {
System.out.println("total " + bd.getTotal()
+ " subTotal " + bd.getSubTotal() + " paid "
+ bd.getTotalPaid()
+ " invoiceDate " + bd.getInvDateStr()
);
SimpleDateFormat formatter1 = new SimpleDateFormat("MM/dd/yyyy");
try {
bd.setInvoiceDate((new java.sql.Date(formatter1.parse(bd.getInvDateStr()).getTime())));
} catch (ParseException ex) {
Logger.getLogger(BillNewAction.class.getName()).log(Level.SEVERE, null, ex);
}
for (BillPaidDetails b : bd.getBillPaidDetailses()) {
System.out.println("type " + b.getPaymentMode() + " amount "
+ b.getAmount()
);
}
System.out.println("product size " + bd.getBillPrList().size());
for (BillProduct b : bd.getBillPrList()) {
System.out.println("id " + b.getId() + " desc "
+ b.getDescription() + " qty " + b.getQty()
+ " sp " + b.getSellingPrice() + " up "
+ b.getUnitPrice() + " " + b.getTotal()
);
}
}
}
public class BillDetails implements java.io.Serializable {
private Long billNo;
private Client client;
private BigDecimal subTotal;
private BigDecimal TotalAmount;//total price
private BigDecimal TotalPaid;//Amount paid for getting items
private BigDecimal vat;
private BigDecimal total;
private String invoiceNo;
private Date invoiceDate;
private String invDateStr;
private List<BillPaidDetails> BillPaidDetailses = new ArrayList<BillPaidDetails>();
private List<BillProduct> billPrList = new ArrayList<BillProduct>();
//getter and setter
}
I have to send data in $scope.bd1[billProductList[0].id] = 1; format to server
Assigning indivisual value passing the data to server but I have dynamic no of values so I am trying
if ($scope.fproducts.length > 0) {
$scope.fproducts.forEach((total, index) => {
Object.entries(total).forEach(([key, value]) => {
console.log(index + " " + key + " " + value);
$scope.bd1[billProductList[${index}].${key}] = value;
});
});
}
that is not working
Consider using the Struts JSON Plugin
The JSON plugin provides a json result type that serializes actions into JSON.
The content-type must be application/json
Action must have a public “setter” method for fields that must be populated.
Supported types for population are: Primitives (int,long…String), Date, List, Map, Primitive Arrays, other class, and Array of Other class.
Any object in JSON, that is to be populated inside a list, or a map, will be of type Map (mapping from properties to values), any whole number will be of type Long, any decimal number will be of type Double, and any array of type List.
Your actions can accept incoming JSON if they are in package which uses json interceptor or by adding reference to it.
This simplifies the AngularJS HTTP POST request:
$scope.bd1 = {
'subTotal': $scope.subTotal,
'total': $scope.finalTotal,
'TotalPaid': $scope.paidAmount,
'invDateStr': $scope.invoiceDate.toISOString(),
'billProductList': $scope.fproducts,
};
$http({
method: 'POST',
url: 'added-invoice',
data: $scope.bd1,
headers: {'Content-Type': 'application/json'}
}).then(function successCallback(response) {
var data = response.data;
if (data.st === 1) {
$scope.success = true;
window.location = 'bhome#!/show-tax';
} else if (data.st === 0) {
$scope.success = false;
$scope.failure = true;
} else if (data.data.st === -1) {
$scope.success = false;
$scope.failure = true;
}
}, function errorCallback(response) {
$scope.success = false;
$scope.failure = true;
});
$scope.bd1[billProductList[${index}].${key}] = value; you are overriding value on this line of code
$scope.bd1[billProductList[${index}${index2}].${key}] you can change shape of object as per you need
$scope.fproducts.forEach((total, index) => {
Object.entries(total).forEach(([key, value],index2) => {
console.log(index + " " + key + " " + value);
$scope.bd1[`billProductList[${index}${index2}].${key}`] = value;
});
})
That may be because console.log(index + " " + key + " " + value) is returning correct value as you are getting inside loop.
try to access the below piece of code, after assigning to $scope.bd1:
Object.entries(total).forEach(([key, value]) => {
$scope.bd1[`billProductList[${index}].${key}`] = value;
console.log($scope.bd1[`billProductList[${index}].${key}`]);
});
And I guess $scope.bd1 is not getting updated hence it is not passing value to server side object.
I'm trying to update an object in Firebase only if one of his property doesn't exist.
The logic so far is : you loop over photos of a defined trip, and if in this photo you don't find the property "location", you update the object by inserting the property "location" (which itself is an object with properties "coord", "locationname", "regioncode", "thumbnailurl").
The problem is that after I load the page, the object "location" is not inserted for photos which don't have the property "location".
My database structure :
My JS :
db.ref('photos/' + owneruid + '/trips/' + tripuid).once('value').then(snap => {
var photos = snap.val()
for (var key in photos) {
console.log('Photo ID is ' + key)
var thisPhoto = photos[key]
this.photos.push(thisPhoto)
var hasLocation = 'location';
if(photos[key].hasOwnProperty(hasLocation)){
console.log("location exists")
}
else{
console.log("NO LOCATION")
var location = {coord:"", locationname:"", regioncode:"", thumbnailurl:""}
function writeLocation(location) {
db.ref('photos/' + owneruid + '/trips/' + tripuid + thisPhoto).update(location)
}
this.photos.push(thisPhoto)
}
}
this.photosDataIsReady = true
})
As we can see in the console, the if condition in the loop works:
Try this code
db.ref('photos/' + owneruid + '/trips/' + tripuid).once('value').then(snap => {
var photos = snap.val()
for (var key in photos) {
console.log('Photo ID is ' + key)
var thisPhoto = photos[key]
this.photos.push(thisPhoto)
var hasLocation = 'location';
if(photos[key].hasOwnProperty(hasLocation)){
console.log("location exists")
}
else{
console.log("NO LOCATION")
var location = {coord:"", locationname:"", regioncode:"", thumbnailurl:""}
db.ref('photos/' + owneruid + '/trips/' + tripuid + thisPhoto).update(location);
this.photos.push(thisPhoto)
}
}
this.photosDataIsReady = true
})
I am working on Firebase pagination using JavaScript. I have implemented a soft delete feature where the record is not deleted in Firebase but deleted in the web display.
So when a soft delete is being done, the visible flag in Firebase becomes false. I want to display on my web form, the contacts whose visible flag is true using JavaScript ( with the NEXT and PREV buttons ).
Since I am new to this, I would love to get suggestions and help!!
A Snapshot of Firebase is as follows:
My code of getting first three records initially is as follows :
function getData() {
var total="";
var firstRef = firebase.database().ref("Persons/").orderByChild("visible").endAt("true").limitToFirst(3);
firstRef.on("value", function (data) {
console.log(data.val());
a = data.val();
var keys = Object.keys(a);
key1 = keys[0];
key2 = keys[1];
console.log("Key 1" + keys[0]);
for (var i = 0; i < keys.length; i++)
{
var k = keys[i];
var fname = a[k].fname;
var lname = a[k].lname;
var mno = a[k].mno;
var email = a[k].email;
var image = a[k].image;
var visible = a[k].visible;
if (visible == true) {
total += "<div><br/></div<div><b>KEY ID: </b><h1>" + k + "</h1></div><div><br/></div><div><img src=" + image + " alt=NoProfilePic class=imgsrc></div><div><b>FIRST NAME : </b>" + fname + "</div><div><b>LAST NAME : </b>" + lname + "</div><div><b>MOBILE NO : </b>" + mno + "</div><div><b>EMAIL : </b>" + email + "</div><div><br/><b><hr><hr></b></div>";
document.getElementById('total').innerHTML = total;
}
}
},
function (error) {
console.log("Error: " + error.code);
});
}
To get the Next three records (which will be called when the NEXT button is pressed ), I have written a code as follows :
function next() {
var total="";
var lastRef = firebase.database().ref("Persons").orderByKey().startAt(key2 + "a").limitToFirst(3);
lastRef.on("value", function (data) {
c = data.val();
var keys = Object.keys(c);
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
var visible = c[k].visible;
if(visible==true)
{
var fname = c[k].fname;
var lname = c[k].lname;
var mno = c[k].mno;
var email = c[k].email;
var image = c[k].image;
total += "<div><br/></div<div><b>KEY ID: </b><h1>" + k + "</h1></div><div><br/></div><div><img src=" + image + " alt=NoProfilePic class=imgsrc></div><div><b>FIRST NAME : </b>" + fname + "</div><div><b>LAST NAME : </b>" + lname + "</div><div><b>MOBILE NO : </b>" + mno + "</div><div><b>EMAIL : </b>" + email + "</div><div><br/><b><hr><hr></b></div>";
document.getElementById('total').innerHTML = total;
}
}
key3=key1;
key4=key2;
key2=keys[2];
key1=keys[0];
},
function (error) {
console.log("Error: " + error.code);
});
}
I am new to Firebase, so please do correct me if I am wrong and also, if anybody could help me with PREV, it would be great!!
Thanks!!
I apologize up front for the possible lack of clarity for this question, but I'm new to Angular.js and my knowledge of it is still slightly hazy. I have done the Angular.js tutorial and googled for answers, but I haven't found any.
I have multiple select/option html elements, not inside a form element, and I'm populating them using AJAX. Each form field is populated by values from a different SharePoint list. I'm wondering if there is a way to implement this using Angular.js?
I would like to consider building this using Angular because I like some of it features such as data-binding, routing, and organizing code by components. But I can't quite grasp how I could implement it in this situation while coding using the DRY principle.
Currently, I have a single AJAX.js file and I have a Javascript file that contains an array of the different endpoints I need to connect to along with specific query parameters. When my page loads, I loop through the arrays and for each element, I call the GET method and pass it the end-point details.
The code then goes on to find the corresponding select element on the page and appends the option element returned by the ajax call.
I'm new to Angular, but from what I understand, I could create a custom component for each select element. I would place the component on the page and all the select and options that are associated with that component would appear there. The examples I've seen demonstrated, associate the ajax call with the code for the component. I'm thinking that I could use a service and have each component dependent on that service and the component would pass it's specific query details to the service's ajax call.
My current code - Program flow: main -> data retrieval -> object creation | main -> form build.
Called from index.html - creates the multiple query strings that are passed to ajax calls - ajax calls are once for each query string - the very last function in the file is a call to another function to build the form elements.
var snbApp = window.snbApp || {};
snbApp.main = (function () {
var main = {};
main.loadCount = 0;
main.init = function () {
function buildSelectOptions(){
//***
//Build select options from multiple SharePoint lists
//***
var listsArray = snbApp.splistarray.getArrayOfListsForObjects();
for(var i = 0; i < listsArray.length; i++){
var listItem = listsArray[i];
var qryStrng = listItem.list +
"?$select=" + listItem.codeDigits + "," + listItem.codeDescription + "," + listItem.ItemStatus + "&$orderby=" + listItem.codeDescription + "&$filter="+listItem.ItemStatus+" eq true" + "&$inlinecount=allpages"
var listDetails = {
listName: listItem.list,
listObj: listItem,
url: "http://myEnv/_vti_bin/listdata.svc/" + listItem.list +
"?$select=" + listItem.codeDigits + "," + listItem.codeDescription + "," + listItem.ItemStatus + "&$orderby=" + listItem.codeDescription + "&$filter="+listItem.ItemStatus+" eq true" + "&$inlinecount=allpages"
};
var clientContext = new SP.ClientContext.get_current();
clientContext.executeQueryAsync(snbApp.dataretriever.letsBuild(listDetails), _onQueryFailed);
}
//***
//Build select option from other API endpoint
//***
var listDetails = {
listName:"SNB_SecondaryActivityCodes",
url: "http://myEnv/requests/odata/v1/Sites?$filter=(IsMajor eq true or IsMinor eq true) and IsActive eq true and IsPending eq false and CodePc ne null and IsSpecialPurpose eq false&$orderby=CodePc"
};
snbApp.dataretriever.letsBuild(listDetails);
}
buildSelectOptions();
//***
//Add delay to populate fields to ensure all data retrieved from AJAX calls
//***
var myObj = setTimeout(delayFieldPopulate,5000);
function delayFieldPopulate(){
var optObj = snbApp.optionsobj.getAllOptions();
var osType = $("input[name=os_platform]:checked").val();
snbApp.formmanager.buildForm(osType, optObj);
}
};
function _onQueryFailed(sender, args) {
alert('Request failed.\nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}
return main
})();
AJAX calls here - called from main/previous file:
var snbApp = window.snbApp || {};
snbApp.dataretriever = (function () {
var listsArray = snbApp.splistarray.getArrayOfListsForObjects();
function getListData(listItem) {
var eventType = event.type;
var baseURL = listItem.url;
$.ajax({
url: baseURL,
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
}
})
.done(function(results){
snbApp.objectbuilderutility.buildObjectFields(results, listItem);
})
.fail(function(xhr, status, errorThrown){
//console.log("Error:" + errorThrown + ": " + myListName);
});
}
function _onQueryFailed(sender, args) {
alert('Request failed.\nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}
return{
letsBuild:function(item) {
getListData(item);
}
};
})();
Builds a item name object - called from recursive AJAX calls / previous file
var snbApp = window.snbApp || {};
snbApp.objectbuilderutility = (function () {
function formatItemCode(itemCode, eventType){
if(eventType !== 'change'){ //for load event
var pattern = /^CE/;
var result = pattern.test(itemCode);
if(result){
return itemCode.slice(2);
}else{
return itemCode.slice(0,3);
}
}else{ //for change event
var pattern = /^CE/;
var result = pattern.test(itemCode);
if(result){
return itemCode.slice(2);
}else{
return itemCode.slice(3);
}
}
}
return{
buildObjectFields: function(returnedObj, listItem){ //results:returnedObj, prevItem:listItem
//***
//For SharePoint list data
//***
if (listItem.listName !== "SNB_SecondaryActivityCodes") {
var theList = listItem.listName;
var firstQueryParam = listItem.listObj.codeDigits;
var secondQueryParam = listItem.listObj.codeDescription;
var returnedItems = returnedObj.d.results;
var bigStringOptions = "";
//regex to search for SecondaryFunctionCodes in list names
var pattern = /SecondaryFunctionCodes/;
var isSecFunction = pattern.test(theList);
if(isSecFunction){
bigStringOptions = "<option value='0' selected>Not Applicable</option>";
}else{
bigStringOptions = "<option value='0' disabled selected>Select Option</option>";
}
$.each(returnedItems, function (index, item) {
var first = "";
var second = "";
for (var key in item) {
if (item.hasOwnProperty(key)) {
if (key != "__metadata") {
if (key == firstQueryParam) {
first = item[key];
}
if (key == secondQueryParam) {
second = item[key];
}
}
}
}
bigStringOptions += "<option value=" + first + " data-code=" + first + ">" + second + "</option>";
});
var str = theList.toLowerCase();
snbApp.optionsobj.updateFunctionOrActivity(theList.toLowerCase(), bigStringOptions);
//***
//For other API
//***
} else {
var theList = listItem.listName;
var bigStringOptions = "<option value='0' disabled selected>Select Option</option>";
var returnedItems = returnedObj.value;
for(var i = 0; i < returnedItems.length; i++){
var item = returnedItems[i];
//***
//change event type means the user selected a field
//***
if(listItem.eventType === "change"){
var siteCodeChange = item.SiteCodePc;
if (typeof siteCodeChange === "string" & siteCodeChange != "null") {
siteCodeChange = siteCodeChange < 6 ? siteCodeChange : siteCodeChange.slice(3);
}
bigStringOptions += "<option value='" + item.Id + "' data-code='" + siteCodeChange + "' data-isDivSite='" + item.IsDivisionSite + "' data-isDistSite='" + item.IsDistrictSite + "' data-divID='" + item.DivisionSiteId + "' data-distID='" + item.DistrictSiteId + "'>(" + siteCodeChange + ") " + item.Name + "</option>";
snbApp.formmanager.buildSelectSiteLocations(bigStringOptions);
//***
//load event which means this happens when the page is loaded
//***
}else{
var siteCodeLoad = item.SiteCodePc;
if (typeof siteCodeLoad === "string" & siteCodeLoad != "null") {
var siteCodeLoad = siteCodeLoad.length < 4 ? siteCodeLoad : siteCodeLoad.slice(0, 3);
}
bigStringOptions += "<option value='" + item.Id + "' data-code='" + siteCodeLoad + "' data-isDivSite='" + item.IsDivisionSite + "' data-isDistSite='" + item.IsDistrictSite + "' data-divID='" + item.DivisionSiteId + "' data-distID='" + item.DistrictSiteId + "'>(" + siteCodeLoad + ") " + item.Name + "</option>";
snbApp.optionsobj.updateFunctionOrActivity(theList.toLowerCase(), bigStringOptions);
}
}
}
}
};
})();
Form management - called from previous file, gets all select elements on page and appends items from the object in previous file to each select element.
var snbApp = window.snbApp || {};
//Direct interface to the form on the page
snbApp.formmanager = (function(){
var form = {};
form.content_holder = document.getElementById("content_holder");
form.sec_act_codes = document.getElementById("snb_secondary_activity_codes");
form.prim_func_codes = document.getElementById("snb_primary_function_codes");
form.sec_func_codes = document.getElementById("snb_secondary_function_codes");
form.sec_func_nums = document.getElementById("snb_secondary_function_numbers");
form.host_options = document.getElementById("snb_host_options");
form.site_locs_div = document.getElementById("site_locations_div");
form.site_locs = document.getElementById("snb_site_locations");
form.dc_or_off_prem_div = document.getElementById("dc_or_off_premise_div");
form.dc_off_prem_codes = document.getElementById("snb_dc_offpremise_codes");
var snb_secondary_activity_codes = "";
var snb_primary_function_codes = "";
var snb_secondary_function_codes = "";
var snb_secondary_function_numbers = "";
var snb_host_options = "";
var snb_site_locations = "";
var snb_dc_op = "";
//builds the server location hosting options selection
function buildLocationTypeSelector() {
var locationOptionsString = "<option value='0' disabled selected>Select Option</option>";
for (var i = 0; i < locationOptions.length; i++) {
var location = locationOptions[i];
locationOptionsString += "<option value=" + location.hostLocale + " data-code=" + location.code + ">" + location.hostLocale + "</option>";
}
$("#snb_host_options").append(locationOptionsString);
}
function buildSiteLocations(bigString){
if(bigString === undefined){
var siteLocs = document.getElementById("snb_site_locations");
var newOption = document.createElement("option");
newOption.setAttribute("value", 0);
newOption.setAttribute("disabled","disabled");
newOption.setAttribute("checked","checked");
var newText = document.createTextNode("Select Option");
newOption.appendChild(newText);
siteLocs.appendChild(newOption);
} else{
var siteLocs = document.getElementById("snb_site_locations");
siteLocs.innerHTML = bigString;
}
}
return {
form:form,
buildSelectSiteLocations: function(bigString){
buildSiteLocations(bigString);
},
buildForm: function (osType, optObj) {
buildLocationTypeSelector();
buildSecondaryFunctionNumberSelector();
buildSiteLocations();
if(osType === 'windows'){
$("#snb_secondary_activity_codes").append(optObj.windows.secondary_activity);
$("#snb_primary_function_codes").append(optObj.windows.primary_function);
$("#snb_secondary_function_codes").append(optObj.windows.secondary_function);
$("#snb_site_locations").append(optObj.windows.site_location);
$("#snb_dc_offpremise_codes").append(optObj.windows.dc_offpremise);
}else{
$("#snb_secondary_activity_codes").append(optObj.unix.secondary_activity);
$("#snb_primary_function_codes").append(optObj.unix.primary_function);
$("#snb_secondary_function_codes").append(optObj.unix.secondary_function);
$("#snb_site_locations").append(optObj.unix.site_location);
$("#snb_dc_offpremise_codes").append(optObj.unix.dc_offpremise);
}
}
};
})();
Thanks in advance.
I am attempting to do a small PoC with PDFs and have run into an issue. I am looking to post a message to a PDF and have the PDF post a message to the browser.
The deets:
I am viewing the PDF in an "object" element in IE9. I am using itextsharp to prefill a pdf template on the server, inject some app level javascript (post message and on message stuff) and then serve that up to the browser via a filestreamresult. I am using Reader 10 to view the PDF in IE9.
What works:
So far, everything works except for the PDF posting a message to the browser. I can post a message to the PDF, from the browser, no problem and all of the fields are prefilled as desired.
What doesn't work:
When I try using this.hostContainer.postMessage(["something","somethingmore"]) I get an Acrobat Escript window that says "hostContainer is not defined". I have also tried using "event.target.hostContainer" but I get "event.target is not defined". I am at a loss of what to do and any insight would be super helpful.
Reference links:
Acrobat Javascript API
Stackoverflow How-To on this topic
Original guide I used
The code:
My form view:
<object id="pdfFrame" style="width:100%;height: 100%;" data="#Url.Action("LoadForm")">No luck :(</object>
My custom javascript string method:
private static string GetCustomJavascript(string existingJavaScript)
{
const string newJs =
"this.disclosed = true; " +
"if (this.external && this.hostContainer) { " +
"function onMessageFunc( stringArray ) { " +
// "var name = this.myDoc.getField(personal.name); " +
// "var login = this.myDoc.getField(personal.loginname); " +
"try{" +
"app.alert(doc.xfa);" +
"console.println('Doc xfa value = ' + doc.xfa);" +
// "event.target.hostContainer.postMessage(['hello from pdf!']);" +
// "this.hostContainer.postMessage(['hello from pdf!']);"+
// "name.value = stringArray[0]; " +
// "login.value = stringArray[1]; " +
"} catch(e){ onErrorFunc(e); } " +
"} " +
"function onErrorFunc( e ) { " +
"console.show(); " +
"console.println(e.toString()); " +
"} " +
"try {" +
"if(!this.hostContainer.messageHandler) { " +
"this.hostContainer.messageHandler = new Object(); " +
"this.hostContainer.messageHandler.myDoc = this; " +
"this.hostContainer.messageHandler.onMessage = onMessageFunc; " +
"this.hostContainer.messageHandler.onError = onErrorFunc; " +
"this.hostContainer.messageHandler.onDisclose = function(){ return true; }; " +
"}" +
"} catch(e){onErrorFunc(e);}" +
"}";
var jsToReturn = existingJavaScript + newJs;
return jsToReturn;
}
My method for filling and sending the form to the browser:
public MemoryStream GetFilledRequestForm(string fileDirectory, User user, FormView formView)
{
var pdfStream = new MemoryStream();
var templateFilePath = GetRequestTypeTemplateFilePath(fileDirectory, _requestModule.FormTemplateFileName);
var pdfReader = new PdfReader(templateFilePath);
// pdfReader.RemoveUsageRights();
var stamper = new PdfStamper(pdfReader, pdfStream);
var formFields = GetFormFields(user, formView, pdfReader);
foreach (var field in formFields.Where(f => f.Value != null))
{
stamper.AcroFields.SetField(field.Name, field.Value);
}
stamper.FormFlattening = false;
var newJs = GetCustomJavascript(stamper.Reader.JavaScript);
stamper.AddJavaScript("newJs", newJs);
stamper.Close();
byte[] byteInfo = pdfStream.ToArray();
var outputStream = new MemoryStream();
outputStream.Write(byteInfo, 0, byteInfo.Length);
outputStream.Position = 0;
return outputStream;
}
Ok, so I have resolved it, with some help of course. I found the key at this stack overflow post. I needed to wait for the object to load before assigning the message handler. Additionally, I needed a global variable in the pdf javascript to be able to post the message.
Html/Javascript: (the key here is the loadListener() function)
#model WebModel.FormView
<object id="pdfFrame" style="width:100%;height: 100%;" data="#Url.Action("LoadForm")">No luck :(</object>
<input id="buttonPost" type="button" value="post to pdf"/>
<script type="text/javascript">
var PDFObject = document.getElementById("pdfFrame");
function loadListener() {
if (typeof PDFObject.readyState === 'undefined') { // ready state only works for IE, which is good because we only need to do this for IE because IE sucks in the first place
debugger;
PDFObject.messageHandler = { onMessage: messageFunc };
return;
}
if (PDFObject.readyState == 4) {
debugger;
PDFObject.messageHandler = { onMessage: messageFunc };
} else {
setTimeout(loadListener, 500);
}
}
function messageFunc(data) {
debugger;
var messagedata = data;
alert('finally!!');
}
function sendToPdf() {
if(PDFObject!= null){
PDFObject.postMessage(
["a", "b"]);
}
}
$('#pdfFrame').ready(function() {
loadListener();
$('#buttonPost').on('click', function() {
sendToPdf();
});
});
</script>
My new function to create the javascript: (the key here is var appHostContainer)
private static string GetCustomJavascript(string existingJavaScript)
{
const string newJs =
"this.disclosed = true; " +
"var appHostContainer = this.hostContainer;" +
"if (this.external && this.hostContainer) { " +
"function onMessageFunc( stringArray ) { " +
// "var name = this.myDoc.getField(personal.name); " +
// "var login = this.myDoc.getField(personal.loginname); " +
"try{" +
"app.alert(stringArray);" +
"appHostContainer.postMessage(['hello from pdf!']);" +
// "name.value = stringArray[0]; " +
// "login.value = stringArray[1]; " +
"} catch(e){ onErrorFunc(e); } " +
"} " +
"function onErrorFunc( e ) { " +
"console.show(); " +
"console.println(e.toString()); " +
"} " +
"try {" +
"if(!this.hostContainer.messageHandler) { " +
"this.hostContainer.messageHandler = new Object(); " +
"this.hostContainer.messageHandler.myDoc = this; " +
"this.hostContainer.messageHandler.onMessage = onMessageFunc; " +
"this.hostContainer.messageHandler.onError = onErrorFunc; " +
"this.hostContainer.messageHandler.onDisclose = function(){ return true; }; " +
"}" +
"} catch(e){onErrorFunc(e);}" +
"}";
var jsToReturn = existingJavaScript + newJs;
return jsToReturn;
}