Load a JavaScript event the last in CRM form - javascript

I have one image saved in Notes with every form in my CRM Online 2013 custom entity. I am using the following code to query the image and show it in an Image tag in a Web Resource on the form. For debugging purposes I was calling the following code through a button, but I want this process of querying the Notes and displaying the image in the web resource to be automatic when the form load. Here is my code:
<html><head><meta charset="utf-8"></head>
<body>
<img id="image" src="nothing.jpg" style="width: 25%; height: auto;" />
<script type="text/javascript">
$(windows).load(function()
{
var recordId = window.parent.Xrm.Page.data.entity.getId();
var serverUrl = Xrm.Page.context.getServerUrl().toString();
var ODATA_ENDPOINT = "XRMServices/2011/OrganizationData.svc";
var objAnnotation = new Object();
ODataPath= serverUrl+ODATA_ENDPOINT;
var temp= "/AnnotationSet?$select=DocumentBody,FileName,MimeType,ObjectId&$filter=ObjectId/Id eq guid'" + recordId + "'";
var result =serverUrl + ODATA_ENDPOINT + temp;
var retrieveRecordsReq = new XMLHttpRequest();
retrieveRecordsReq.open('GET', ODataPath + temp, false);
retrieveRecordsReq.setRequestHeader("Accept", "application/json");
retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
retrieveRecordsReq.onreadystatechange = function ()
{
if (this.readyState == 4 /* complete */)
{
if (this.status == 200)
{
this.onreadystatechange = null; //avoids memory leaks
var data = JSON.parse(this.responseText, SDK.REST._dateReviver);
if (data && data.d && data.d.results)
{
SuccessFunc(JSON.parse(this.responseText, SDK.REST._dateReviver).d.results);
}
}
else
{
alert(SDK.REST._errorHandler(this));
}
}
};
var x = new XMLHttpRequest();
x.open("GET", result, true);
x.onreadystatechange = function ()
{
if (x.readyState == 4 && x.status == 200)
{
var doc = x.responseXML;
var title = doc.getElementsByTagName("feed")[0].getElementsByTagName("entry")[0].getElementsByTagName("content")[0].getElementsByTagName("m:properties")[0].getElementsByTagName("d:DocumentBody")[0].textContent;
document.getElementById('image').src ="data:image/png;base64,"+title;
}
};
x.send(null);
});
</script>
</body></html>
I have removed the button tag..now I want this the query to happen on page Load, but nothing happens when I refresh the form. In my opinion the function loads before the annotation loads. Is there a way to make it wait and load the last?

If you want to wait for the parent window to load I think $(windows).load(myFunction); should do the trick.
Maybe $ is undefined because you did not add jQuery to your webressource.
There are also a few little mistakes and unattractive things:
First:
You will get a wrong server url.
If you want to access the Xrm-object in a webresource you always have to use window.parent.Xrm or you put it in a variable var Xrm = window.parent.Xrm;
For example:
var Xrm = window.parent.Xrm;
var recordId = Xrm.Page.data.entity.getId();
var serverUrl = Xrm.Page.context.getServerUrl().toString();
Second:
The ODataPath variable is not declared. Use var ODataPath= serverUrl+ODATA_ENDPOINT; instead. By the way the value of the ODataPath has nothing to do with OData. It is more the REST-Endpoint of Dynamics CRM.
My script would look like this:
var Xrm, recordId, serverUrl, restEndpointUrl, odataQuery, fullRequestUrl, xmlRequest;
Xrm = window.parent.Xrm;
recordId = Xrm.Page.data.entity.getId();
serverUrl = Xrm.Page.context.getServerUrl().toString();
restEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc";
^ I think a '/' was missing there
odataQuery = "/AnnotationSet?$select=DocumentBody,FileName,MimeType,ObjectId&$filter=ObjectId/Id eq guid'" + recordId + "'";
fullRequestUrl = restEndpointUrl + odataQuery;
I also dont understand why you use the second HttpRequest.
All of this code is not tested.

Related

Local Storage is not shared between pages

I have an epub3 book with 2 pages as well as a Table of Contents Page. I am viewing this book in Apple's Books, their inbuilt epub3 reader, on Mac OSX. The two pages appear side by side. The first page is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=500, height=600"/>
</head>
<body>
<p id="result"></p>
<script>
//<![CDATA[
var current_page = "1";
var other_page = "2";
var t = 0;
setInterval(function() {
var d = new Date();
var storage = localStorage;
storage.setItem("t"+ current_page, d.toLocaleString());
document.getElementById("result").innerHTML = storage.getItem("t"+ current_page) +" "+storage.getItem("t"+ other_page);
}, 1000);
//]]>
</script>
</body>
</html>
and the only thing different in my second page is:
var current_page = "2";
var other_page = "1";
So every second, Page 1 saves the current time to Local Storage as t1, and Page 2 does the same for the value t2. At the same time, both pages are reading both t1 and t2 from Local Storage, before their values are displayed to screen. However in ibooks, Page 1 only manages to display the current value for t2 when the page is reloaded - like when I flip to the Table of Contents and then back to Page 1 and 2 again. With something similar happening for Page 2 with regard to t1.
So at time 21:10:00, Page 1 might display:
08/09/19, 21:09:18 08/09/19, 21:08:58
and Page 2:
08/09/19, 21:09:22 08/09/19, 21:08:01
I also tried using Session Data but Page 1 can't ever read t2 and Page 2 can't read t1. So, this would be displayed instead:
08/09/19, 21:09:18 null
I can think of several applications where it would be very useful for Pages to communicate with each other.
For example, if a video is playing on one page, it would be useful to stop it if a video on another page is started. This would normally be done using Session Storage. This is related to my own use case and the reason I started exploring this problem.
Likewise, if the user is asked on Page 1 to enters the name of the main character of the story, then that entry should appear immediately on Page 2 once it is entered.
Is there any other way for Pages to communicate with each other in epub3 other than Local or Session Storage?
I dont know epub3 and dont have a MAC to test, but here are four possible solutions that come to my mind:
Cookies
It is not as performant as localStorage for that use-case, but if you dont have many options, better that than nothing.
Functions to create, read and delete cookies (Credits to https://stackoverflow.com/a/28230846/9150652):
function setCookie(name,value,days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
document.cookie = name+'=; Max-Age=-99999999;';
}
Usage for your example:
<script>
//<![CDATA[
var current_page = "1";
var other_page = "2";
var t = 0;
setInterval(function() {
var d = new Date();
setCookie("t"+ current_page, d.toLocaleString(), 100); // 100 days
document.getElementById("result").innerHTML = getCookie("t"+ current_page) +" "+getCookie("t"+ other_page);
}, 1000);
//]]>
</script>
BroadcastChannel
BroadcastChannel is a very new functionality, so it might not be supported by the "Books" app. But here is a concept:
<script>
//<![CDATA[
var broadcaster = new BroadcastChannel('test');
var current_page = "1";
var other_page = "2";
var t = 0;
setInterval(function() {
var d = new Date();
// Send message to all other tabs with BroadcastChannel('test')
bc.postMessage({
senderPage: "t"+ current_page,
date: d.toLocaleString()
});
}, 1000);
broadcaster.onmessage = (result) => {
if(result.senderPage == "t"+ other_page) { // If the message is from the other page
// Set HTML to current date + sent Date from other page
var d = new Date();
document.getElementById("result").innerHTML = d.toLocaleString() +" "+result.date;
}
};
//]]>
</script>
Some sort of Backend
If none of the above works, you probably have no other option, than to use some sort of backend, to provide and save the data
If it is just for you, I suggest you to use a free tier of Firebase or MongoDB Atlas, as they both provide quite some value on their free tier.
If you do it with a Backend, it could be done with something like this:
<script>
//<![CDATA[
var current_page = "1";
var other_page = "2";
var lastLocalDate = new Date();
const serverUrl = "http://someUrl.com/endpoint/"
// Gets the latest date of the other page via ajax
function getUpdate() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
// If successful, update HTML
if (xmlhttp.status == 200) {
document.getElementById("result").innerHTML = lastLocalDate.toLocaleString() +" "+xhr.responseText;
}
// Update the date of this page anyways
sendUpdate();
}
};
// GET request with parameter requestingPage, which is the other page
xmlhttp.open("GET", serverUrl, true);
xmlhttp.send(`requestingPage=${other_page}`);
}
// Sends the current date of this page to the webserver
function sendUpdate() {
var xmlhttp = new XMLHttpRequest();
// No need to check if successful, just update the page again
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
getUpdate();
}
};
lastLocalDate = new Date();
// POST request with parameters page and date
xmlhttp.open("POST", serverUrl, true);
xmlhttp.send(`sendingPage=${current_page}&data=${lastLocalDate.toLocaleString()}`);
}
// Start with sending an update (so that lastLocalDate is at least sent once to the server)
sendUpdate();
//]]>
</script>
And some methods in your backend that need to look something like this (note that this is not valid code in any language):
#GET
function getDate(requestingPageId)
find latest entry with page.id == requestingPageId
return page.date
#POST
function saveDate(savingPage, savingDate)
store new page element with
page.id = savingPage
page.date = savingDate
And a collection in your database looking like this:
[
{
id: 1,
date: "date"
},{
id: 2,
date: "date"
},{
id: 2,
date: "date"
},{
id: 1,
date: "date"
},
// ...
]
Window References
If the Books app opens the second tab from the first tab, it might be worth to look into:
Window.postMessage()
With its functions:
Window.open()
to open the second tab and get a reference to it
And Window.opener to get a reference to the opener

How to bind parameter to URL

This is my jsp code. I want to bind the catid parameter to url when I call getproductsub() and send ajax request.
r.open("GET", "url?catid=" + catid,true);
above line seems an error of my code.How can I fix it.
<select class="form-control" id="pcategory" name="pcategory" onchange="getproductsub();">
<script>
function getproductsub() {
var catid = document.getElementById('pcategory').value;
var url = window.location.href;
var r = new XMLHttpRequest();
r.onreadystatechange = function() {
if (r.readyState === 4 && r.status === 200) {}
};
r.open("GET", "url?catid=" + catid, true);
r.send();
}
</script>
Note that window.location.href gives the complete location including the parameters in the url at the current time. So ? might be included in it.
You can either use
var url = window.document.location.pathname;
And concat the url to the String passed to open().
r.open("GET", url + "?catid=" + catid, true);
OR
Use getRequestURL() as you are coding in jsp.
r.open("GET", "<%= request.getRequestURL()%>?catid=" + catid, true);

TVMaze api error

I am creating a site for listing TV shows and I am using TVMaze api for it. I am beginner in working with JSON so maybe my problem is that, but here is the weird thing happening.
My table is generated with this code:
var keyword = "";
var $url = "";
$('#submit').on('click', function (e) {
//e.preventDefault();
keyword = $('#search').val();
window.sessionStorage['keyword'] = keyword;
});
if (!window.sessionStorage['keyword']) {
$url = " http://api.tvmaze.com/shows?page=1";
} else {
keyword = window.sessionStorage['keyword'].toString();
keyword = keyword.toLowerCase().replace(/\s/g, "");
$url = "http://api.tvmaze.com/search/shows?q=" + keyword;
//alert($url);
}
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var $obj = JSON.parse(this.responseText);
for (var i = 0; i <= $obj.length - 1; i++) {
var $item = '<div> \
<div>\
<h2>' + $obj[i].name + '</h2> \
<div> ' + $obj[i].rating.average + ' </div>\
<p>' + $obj[i].summary + '</p>\
Track\
</div>\
</div>';
$('.show-items-container').append($item);
}
}
};
//alert($url);
xmlhttp.open("GET", $url, true);
xmlhttp.send();
So first it checks if there is keyword entered in a search bar and if there isn't it sends a request to the /page=1, and if there is a keyword entered, it should print the show. But, in my case, it reads to url like it is supposed to, but nothing shows up. And if I search that link in the browser it lists the correct show.
For example if I put 'kirby' in the search bar, it reads this url -> http://api.tvmaze.com/search/shows?q=kirby , but nothing shows in the table and there are no errors in the console. If you enter that same url in the browser, it works.
Can anyone tell me what the problem is?
Looks like onclick you are not making the xhr request. You call xmlhttp.open and xmlhttp.send outside of the click event so nothing happens on click. Also I noticed you were accessing the wrong property it should be $obj[i].show.___ vs $obj[i].___
var keyword = "";
var $url = "";
var xmlhttp = new XMLHttpRequest();
function makeRequest() {
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// clear the current search results
$('.show-items-container').empty();
var $obj = JSON.parse(this.responseText);
for (var i = 0; i <= $obj.length - 1; i++) {
// make sure you access the correct property
var $item = `<div>
<div>
<h2> ${$obj[i].show.name} </h2>
<div> ${$obj[i].show.rating.average} </div>
<p> ${$obj[i].show.summary} </p>
Track
</div>
</div>`;
$('.show-items-container').append($item);
}
}
}
// make the xhr request on click
xmlhttp.open("GET", $url, true);
xmlhttp.send();
}
$('#submit').on('click', function(e) {
keyword = $('#search').val();
$url = "https://api.tvmaze.com/search/shows?q=" + keyword;
// call on click
makeRequest();
});
// call on page load
makeRequest();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='search' />
<button type="button" id='submit'>Submit </button>
<div class="show-items-container">
</div>

Javascript - cycle through xml elements and display in turn

I am trying to create an application that will show, and periodically change, a paragraph of text (like a news article or similar).
I want the data to come from an xml file so other people can add stories/remove old stories etc.
I'm trying to get my JavaScript to populate a single html field with data from an xml file. Then after a given time, for now we'll say 4 seconds, it will change to the next piece of data.
Below is a very crude version of what I've been trying to do:
HMTL:
<head>
<script src="script.js"></script>
</head>
<body>
<div id="text"></div>
</body>
XML:
<document>
<text>one</text>
<text>two</text>
<text>three</text>
</document>
JavaScript:
var timer = setInterval(addText,4000);
var xhttp = new XMLHttpRequest();
xhttp.onreadystaechange = function() {
if(this.readyState == 4 && this.status == 200) {
addText(this);
}
};
function addText(xml) {
var xmlDoc = xml.responseXML;
var count = 0;
var max = xmlDoc.GetElementsByTagName("text");
document.getElementById("text").innerHTML =
xmlDoc.getElementByTagName("text")[count].childNodes[0].nodeValue;
if (count < max.length) {
count++;
} else {
count = 0;
}
}
xhttp.open("GET", "XMLFile.xml",true);
xhttp.send();
The current problem I am experiencing is that the first xml field populates successfully, but then I get an error saying "Unable to get property 'responseXML' of undefined or null reference".
Ideally what I'd also like is for the xml document to be opened everytime the function occurs, so the application doesn't have to be restarted if extra data is added to the xml file - if that makes sense (and is possible)
You can place addText in the scope of onreadystatechange handler. Something like this.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
var xmlDoc = this.responseXML;
var count = 0;
var xText = xmlDoc.getElementsByTagName("text");
var max = xText.length;
var docText = document.getElementById("text");
function addText() {
//docText, xText and count are available from parent scope
docText.innerHTML =
xText[(count++) % max].childNodes[0].nodeValue;
}
var timer = setInterval(addText,4000);
}
};
xhttp.open("GET", "XMLFile.xml",true);
xhttp.send();

How to insert form into mysql without leaving the page (javascript+html)

I'm trying to insert a new user into mysql. I have tried to use jQuery, but it doesn't seem to be working. I tried to use pure javascript, but it's the same. It has no response after I click on the button. What's wrong?
var regBtn = document.getElementById("regBtn");
regBtn.addEventListener("click", submitForm, false);
function submitForm() {
var acR = document.getElementById("ac2");
var pw1 = document.getElementById("pw1");
var shop = document.getElementById("shop");
var http = new XMLHttpRequest();
http.open("POST", "http://xyz.php", true);
http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
var params = "ac=" + acR + "&pw1="+pw1 "&shop="+ shop;
http.send(params);
http.onload = function() {
alert(http.responseText);
};
}
There's a quite a few problems in your JS code, I've tidied it up here and run it locally to a page called xyz.php, so that'll get the AJAX call to work but you'll need to post your PHP code to get any help with your DB queries
var regBtn = document.getElementById("regBtn");
regBtn.addEventListener("click", submitForm, false);
function submitForm() {
var acR = document.getElementById("ac2");
var pw1 = document.getElementById("pw1");
var http = new XMLHttpRequest();
// removed the http:// protocol, assuming you're going for a local AJAX call
http.open("POST", "xyz.php", true);
http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
// get values of the form fields, don't submit the full element
// also added the plus (+) character before the final pw1
var params = "ac=" + acR.value + "&pw1=" + pw1.value;
http.send(params);
http.onload = function() {
alert(http.responseText);
}
}
I've attached a screen shot showing Chrome Dev Tools happily recording successful AJAX requests
Try to use a JQuery post.
var acR = document.getElementById("ac2");
var pw1 = document.getElementById("pw1");
$.post( "xyz.php", { ac: acR, pw1: pw1 })
.done(function( data ) {
alert( "Data inserted: " + data );
});
Backend handles this post and then implement the insert action for example in NodeJs(express)
app.post("/xyz", function(req, res, next) {
var obj = {};
obj[acR] = body.ac;
obj[pw1] = body.pw1;
mysql.insert(obj);
});

Categories