I'm working with a Google-Extention which allows me to open a new tab containing a form. After the form gets filled out and saved, every time I open this tab again the form should be prefilled with the data saved earlier.
Here is how the data gets saved: WORKS!
function saveCheckoutData() {
var vName = document.getElementById('txbx_name').value;
chrome.storage.sync.set({'name': vName}, function() {
console.log(vName);
})
}
Here is how i get the data: WORKS!
function getdata() {
chrome.storage.sync.get('name', function(data) {
var name = data.name;
if(name != null){
document.getElementById("txbx_name").value = name;
}
});
}
The code above gets called on button click and works perfectly!
But as soon I try to do this when the tab gets opened it doesn't work (the tab gets opened but there is nothing in the textbox): DOESN'T WORK!
function configAutofill(){
var newURL = "autofill_data.html";
chrome.tabs.create({ url: newURL });
chrome.storage.sync.get('name', function(data) {
var name = data.name;
if(name != null){
document.getElementById("txbx_name").value = name;
}
});
}
Does some one have an Idea why these lines do not work when creating a new tab?
Many thanks in advance.
Here's a question for you.
After creating a new tab, you access document.getElementById. Yes, but which document?
In your case, it would be the page calling create - which is not the created page.
In your case, it seems like you're opening a page that's part of the extension. Then you should just include code in it that will run on load.
You may want to check document.readyState:
if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', getdata);
} else {
getdata();
}
If you're trying to do this with a webpage, you'll need a content script. Again, those normally execute after DOM is parsed - so just call getdata() at top level.
Related
I have a page that will open a popup and after something is done on that popup and user close it I want to get data from table / tds. Here is my calling function:
function clicked() {
windowOpener("SiteMap.html");
popupWin.onbeforeunload = function () {
var a = $("#drawTable", popupWin.document);
var tds = $(a).find("td");
tds.each(function () {
var p = $(this).data('point');
if (JSON.stringify(p.values) !== JSON.stringify(point.values)) { //here comes error, to this line
console.log(p.values);
}
})
};
}
.data('point') is created and populated already on that popup page, but still I am getting that $(this).data('point') is undefined. So, is it possible that in that point data is already destroyed? What is your recommendation how to deal with this?
thanks
I am playing with jquery and js, trying to build an ajax overlay image viewer for a PHP website. With this code included at the bottom of the 'gallery page', the viewer opens and i can navigate with next and previous links inside the viewer. But the back button and the history is hard to understand. The browser often shows only the response of the ajax call, without the underlying page and css files, after some clicks back.
Perhaps somebody knows what is generally happening in such a case? I would like to understand why back sometimes results in a broken page, i.e. only the ajax response.
<script type="text/javascript">
$(document).ready(function() {
function loadOverlay(href) {
$.ajax({
url: href,
})
.done(function( data ) {
var theoverlay = $('#flvr_overlay');
theoverlay.html( data );
var zoompic = $('#zoompic');
zoompic.load(function() {
var nih = zoompic.prop('naturalHeight');
var photobox = $('#photobox');
if($(window).width() >= 750){
photobox.css('height',nih);
}
theoverlay.show();
$('body').css('overflow-y','hidden');
$(window).resize(function () {
var viewportWidth = $(window).width();
if (viewportWidth < 750) {
photobox.css('height','auto');
zoompic.removeClass('translatecenter');
}else{
photobox.css('height',nih);
zoompic.addClass('translatecenter');
}
});
});
});
return false;
}
var inithref = window.location.href;
$(window).on('popstate', function (e) {
if (e.originalEvent.state !== null) {
//load next/previous
loadOverlay(location.href);
} else {
//close overlay
$('#flvr_overlay').hide().empty();
$('body').css('overflow-y','scroll');
history.replaceState(null, inithref, inithref);
}
});
$(document).on('click', '.overlay', function () {
var href = $(this).attr('href');
history.pushState({}, href, href);
loadOverlay(href);
return false;
});
});
</script>
edit
clicking forward works:
/photos (normal page)
/photos/123 (overlay with '/photos' below)
/locations/x (normal page)
/photos/567 (overlay with '/locations/x' below)
clicking back gives me the broken view at point 2.
Do you need to prevent the default behaviour in your popstate to prevent the browser from actually navigating back to the previous page?
you have to manage it by own code.
You have a few options.
Use localstorage to remember the last query
Use cookies (but don't)
Use the hash as you tried with document.location.hash = "last search" to update the url. You would look at the hash again and if it is set then do another ajax to populate the data. If you had done localstorage then you could just cache the last ajax request.
I would go with the localstorage and the hash solution because that's what some websites do. You can also copy and paste a URL and it will just load the same query. This is pretty nice and I would say very accessible
Changing to document.location.hash = "latest search" didn't change anything.t.
This goes into the rest of the jQuery code:
// Replace the search result table on load.
if (('localStorage' in window) && window['localStorage'] !== null) {
if ('myTable' in localStorage && window.location.hash) {
$("#myTable").html(localStorage.getItem('myTable'));
}
}
// Save the search result table when leaving the page.
$(window).unload(function () {
if (('localStorage' in window) && window['localStorage'] !== null) {
var form = $("#myTable").html();
localStorage.setItem('myTable', form);
}
});
Another solution is that use INPUT fields to preserved while using back button. So, I do like that :
My page contains an input hidden like that :
Once ajax content is dynamicaly loaded, I backup content into my hidden field before displaying it:
function loadAlaxContent()
{
var xmlRequest = $.ajax({
//prepare ajax request
// ...
}).done( function(htmlData) {
// save content
$('#bfCache').val( $('#bfCache').val() + htmlData);
// display it
displayAjaxContent(htmlData);
});
}
And last thing to do is to test the hidden field value at page loading. If it contains something, that because the back button has been used, so, we just have to display it.
jQuery(document).ready(function($) {
htmlData = $('#bfCache').val();
if(htmlData)
displayAjaxContent( htmlData );
});
Before I get into the long-winded explanation and the code, let me just say that I understand that my implementation of this system is a bit of a hack-job. The goal was to implement a linking feature on a SPA application without completely overhauling what was already done with Angular and the Bootstrap modals. I'll wager that I probably could have accomplished something better with directives, but my understanding of directives is lacking.
The following is a function that is launched when the system detects a change in the URL. The new URL parameters are passed and are used to query the back-end for content.
function handleUrlParamsModalLaunch(data) {
/*Ensure modal is not displaying any data*/
vm.modalData = {};
vm.selectedTab = null;
/*Show modal loading gif*/
vm.isModalLoading = true;
$("#contentPartModal").modal();
/*Call the content service to return the clicked content article*/
contentpartservice.getContentItem(data.id, data.type).then(function (contentItem) {
if (contentItem) {
vm.isModalLoading = false;
vm.modalData = contentItem;
return;
} else {
closeModal("#contentPartModal").then(function () {
vm.isModalLoading = false;
logger.error('An error occurred while fetching content');
});
return;
}
}, function (error) {
closeModal("#contentPartModal").then(function () {
vm.isModalLoading = false;
logger.error('An error occurred while fetching content');
});
return;
});
}
The following function is run when a link is clicked. It adds the parameters needed to retrieve content from the back-end to the URL.
function setUrl(contentId, contentType) {
var urlParams = $location.search();
if (urlParams.q) {
$location.search({ q: urlParams.q, type: contentType, id: contentId });
} else {
$location.search({ type: contentType, id: contentId });
}
return;
}
The following is where the solution starts to look like a hack job. I need to remove the parameters from the URL when the modal closes, but I couldn't find a way to catch the Bootstrap modal close event from the scope of my Angular controller (where the above functions are being called). Instead, I wrote the following JavaScript code in script tags that does it without Angular's $location dependency.
<script>
/*
* Detect the closing of a modal window and modify the URL to no longer display linking information.
* Not handled in Angular because Angular lacks a suitable way to detect a bootstrap modal close.
*/
$('#contentPartModal').on('hidden.bs.modal', function () {
var pageUrl = $.url();
var pageParams = pageUrl.param();
if (pageParams.q) {
if (history.pushState) {
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?q=' + pageParams.q;
window.history.pushState({ path: newurl }, '', newurl);
}
} else {
if (history.pushState) {
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname;
window.history.pushState({ path: newurl }, '', newurl);
}
}
});
</script>
Here is the resulting bug. The first time you click on a link, all of these functions run fine. The modal is opened with the correct data being displayed. When you close the modal, the URL parameters are removed from view. When you go to click on another link, the setUrl function is called, but the URL doesn't actually change. This results in the modal pop-up not opening. A second click on any link, and everything works as expected. The resulting bug is that each link needs to be clicked twice after the first time the modal has been opened.
Any hints to the cause of this bug would be much appreciated. I'd also accept an idea for a better implementation that would help me circumvent the issue altogether.
Thanks,
Matt
I am currently developing a web app that pulls metadata from a webservice.
It currently works in all browsers except that we get this weird issue on Windows Phone in Internet Explorer.
If you have a clear cache (first time load) it works with out a hitch, however once you refresh the page or navigate away and come back to the page the drop down lists fail to display data returned from the web service
Before:
After:
We are using standard jQuery $.ajax calls to a local webservice
It appears that in the after situation the success call back is being fired but the dropdowns aren't being rendered , and again this only happens after the page has successfully loaded once from a clean cache state and works fine in all other mobile browsers
the jquery code being used for the web service
function getAllPublications() {
$('.error').addClass('dn');
$('#selectYear').prop('disabled', 'disabled');
$('#selectVehicle').prop('disabled', 'disabled');
$('#selectManual').prop('disabled', 'disabled');
$('.manual-section').hide();
$.ajax({
url: "/_Global/HttpHandlers/OwnersManuals/GetPublications.ashx",
dataType: "json",
type: "GET",
success: function (data) {
$('.manuals-loader').hide();
if (data.getPublicationYearModelDataResult.ErrorCode == 0) {
allResults = data.getPublicationYearModelDataResult;
extractUniqueYears(allResults);
populateYearsDropdown();
} else {
$('.error.no-publication-error').removeClass('dn');
}
debugLog(JSON.stringify(data));
},
error: function (error) {
$('.manuals-loader').hide();
$('.error.api-error').removeClass('dn');
console.log(error);
}
});
}
function populateYearsDropdown() {
$('#selectYear')
.empty()
.append($("<option />").val('-').html(__pleaseSelect))
.removeAttr('disabled');
$.each(years, function (val, text) {
$('#selectYear').append($("<option />").val(text).html(text));
});
}
function extractUniqueYears(result) {
years = [];
if (result.PublicationYearModels != null) {
$(result.PublicationYearModels).each(function (i, item) {
if (item.YearModels != null) {
$(item.YearModels).each(function (j, subItem) {
var year = subItem.year;
if (!checkIfYearExists(year))
years[years.length] = year;
});
}
});
}
years.sort();
years.reverse();
}
Note: I have tried adding no cache and cache expiration headers to the page and also tried using cache expiration meta tags on the page as well with no effect
You should be able to trick browser into thinking that you're hitting the page for the first time using Location.reload(forcedReload). Here's an example using cookies to prevent you from getting stuck in an infinite refresh loop:
var ie_mobile_reload = false, FORCED_RELOAD = true;
if /refresh=true/.test(document.cookie) {
document.cookie = 'refresh=;'; /* Remove the refresh cookie */
ie_mobile_reload = true;
location.reload(FORCED_RELOAD);
}
/* IE Mobile only */
if /IEMobile/.test(navigator.userAgent) {
window.onbeforeunload = function() {
if (ie_mobile_reload) {
document.cookie = 'refresh=true'; /* Set the refresh cookie */
}
};
}
I set FORCED_RELOAD = true to skip the cache and cause the page to be reloaded directly from the server.
We ended up changing how the dropdown is initialized.
The problem was the dropdown list init was firing too late because of the caching issue on windows and wiping out the dropdown list content after it had been populated
we moved the logic into the DDL fill function and it fixed the issue so it clears all three DDLs when it is initially populated in the ajax function instead
I am trying to display a 'mask' on my client while a file is dynamically generated server side. Seems like the recommend work around for this (since its not ajax) is to use an iframe and listen from the onload or done event to determine when the file has actually shipped to the client from the server.
here is my angular code:
var url = // url to my api
var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
e.load(function() {
$scope.$apply(function() {
$scope.exporting = false; // this will remove the mask/spinner
});
});
angular.element('body').append(e);
This works great in Firefox but no luck in Chrome. I have also tried to use the onload function:
e.onload = function() { //unmask here }
But I did not have any luck there either.
Ideas?
Unfortunately it is not possible to use an iframe's onload event in Chrome if the content is an attachment. This answer may provide you with an idea of how you can work around it.
I hate this, but I couldn't find any other way than checking whether it is still loading or not except by checking at intervals.
var timer = setInterval(function () {
iframe = document.getElementById('iframedownload');
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
// Check if loading is complete
if (iframeDoc.readyState == 'complete' || iframeDoc.readyState == 'interactive') {
loadingOff();
clearInterval(timer);
return;
}
}, 4000);
You can do it in another way:
In the main document:
function iframeLoaded() {
$scope.$apply(function() {
$scope.exporting = false; // this will remove the mask/spinner
});
}
var url = // url to my api
var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
angular.element('body').append(e);
In the iframe document (this is, inside the html of the page referenced by url)
window.onload = function() {
parent.iframeLoaded();
}
This will work if the main page, and the page inside the iframe are in the same domain.
Actually, you can access the parent through:
window.parent
parent
//and, if the parent is the top-level document, and not inside another frame
top
window.top
It's safer to use window.parent since the variables parent and top could be overwritten (usually not intended).
you have to consider 2 points:
1- first of all, if your url has different domain name, it is not possible to do this except when you have access to the other domain to add the Access-Control-Allow-Origin: * header, to fix this go to this link.
2- but if it has the same domain or you have added Access-Control-Allow-Origin: * to the headers of your domain, you can do what you want like this:
var url = // url to my api
var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
angular.element(document.body).append(e);
e[0].contentWindow.onload = function() {
$scope.$apply(function() {
$scope.exporting = false; // this will remove the mask/spinner
});
};
I have done this in all kinds of browsers.
I had problems with the iframe taking too long to load. The iframe registered as loaded while the request wasn't handled. I came up with the following solution:
JS
Function:
function iframeReloaded(iframe, callback) {
let state = iframe.contentDocument.readyState;
let checkLoad = setInterval(() => {
if (state !== iframe.contentDocument.readyState) {
if (iframe.contentDocument.readyState === 'complete') {
clearInterval(checkLoad);
callback();
}
state = iframe.contentDocument.readyState;
}
}, 200)
}
Usage:
iframeReloaded(iframe[0], function () {
console.log('Reloaded');
})
JQuery
Function:
$.fn.iframeReloaded = function (callback) {
if (!this.is('iframe')) {
throw new Error('The element is not an iFrame, please provide the correct element');
}
let iframe = this[0];
let state = iframe.contentDocument.readyState;
let checkLoad = setInterval(() => {
if (state !== iframe.contentDocument.readyState) {
if (iframe.contentDocument.readyState === 'complete') {
clearInterval(checkLoad);
callback();
}
state = iframe.contentDocument.readyState;
}
}, 200)
}
Usage:
iframe.iframeReloaded(function () {
console.log('Reloaded');
})
I've just noticed that Chrome is not always firing the load event for the main page so this could have an effect on iframes too as they are basically treated the same way.
Use Dev Tools or the Performance api to check if the load event is being fired at all.
I just checked http://ee.co.uk/ and if you open the console and enter window.performance.timing you'll find the entries for domComplete, loadEventStart and loadEventEnd are 0 - at least at this current time:)
Looks like there is a problem with Chrome here - I've checked it on 2 PCs using the latest version 31.0.1650.63.
Update: checked ee again and load event fired but not on subsequent reloads so this is intermittent and may possibly be related to loading errors on their site. But the load event should fire whatever.
This problem has occurred on 5 or 6 sites for me now in the last day since I noticed my own site monitoring occasionally failed. Only just pinpointed the cause to this. I need some beauty sleep then I'll investigate further when I'm more awake.