I am trying to scroll to an element within an HTML5 object like so:
HTML with angular:
SHOW ME
This is the object I am using to pull in an html file locally.
<object type="text/html" data="sample.html" id="site-frame">
Inside sample.html, I have a div at the bottom of the page:
div id="anchor5" class="anchor">Anchor 5 of 5</div>
function within controller:
$scope.gotoAnchor = function(x) {
var newHash = 'anchor' + x;
if ($location.hash() !== newHash) {
$location.hash('anchor' + x);
} else {
$anchorScroll();
}
};
if I place the anchor5 div outside of the object, it works, but not while inside the of the object. I am looking to go INTO the Object and scroll to the div. Any help would be awesome!
Figured it out. Here is the code I used:
var goToLink = function(link){
var element = document.getElementById('site-frame').contentWindow.document.getElementById(link)
element.scrollIntoView({block: "end", behavior: "smooth"});
}
I was able to use the previous comment of scrollIntoView() using the options and this other answer - How to pick element inside iframe using document.getElementById
Related
Context: I'm lazy, and I'm trying to dynamically/automatically create menu buttons which are hyperlinked to the headers of a page with raw JavaScript.
My site loads the content of the body from an external file located at the same folder with document.onload, and I'm trying to set up a menu function, which then should load the default page's menu items. Loading the menu manually each time I change from one page to another works, as I've included loadMenues(thispage) on the end loadContents(), but it doesn't work as soon as the page is loaded, as loading the body content does. I don't understand this behaviour.
function setVisible(thisdiv){
var alldivs = document.getElementsByClassName("container");
[].forEach.call(alldivs, function(uniquediv){
document.getElementById(uniquediv.id).style.display = "none";
return;
});
document.getElementById(thisdiv).style.display = "block";
window.scrollTo(0,0);
loadMenues(thisdiv);
}
window.onload = function(){
loadContent("personalinfo");
loadContent("contactdetails");
setVisible("personalinfo");
loadMenues("personalinfo");
}
I'm explaining this, secondary question, in order to contextualize my main problem.
loadContents(file) is a function which extracts the contents from the requested file. The layout of each of these files is the same, pretty much, with each section of the file being separated by a custompadding div, where its first child is a h1 element as shown below:
<html>
<div class="custompadding">
<h1 id="headerpersonaldetails">Personal details</h1>
<p>Lorem ipsum</p>
</div>
<div class="custompadding">
<h1 id="headercontactdetails">Contact details</h1>
<p>Lorem ipsum</p>
</div>
</html>
I'm trying to set up a menu item for each of these headings, which scrolls to the clicked-on header. Setting up each menu-item manually works as expected, but I want to automatize it, so changing any file will automatically add the menu items to whichever page we change to. Following is my code which adds these elements to the divisor, but I'm having issues handling the onclick function.
function loadMenues(file) {
var rightmenu = document.getElementById("right-menu");
while(rightmenu.firstChild){
rightmenu.removeChild(rightmenu.firstChild);
}
[].forEach.call(document.getElementById(file).children, function(custompaddingchild) {
console.log(custompaddingchild);
headerelement = custompaddingchild.getElementsByTagName("h1")[0]
newbutton = document.createElement("div");
newbutton.setAttribute("class", "menu-item");
let movehere = function() { location.href="#"+headerelement.id; console.log(headerelement.id); }
newbutton.onclick = movehere;
/*rightmenu = document.getElementById("right-menu");*/
buttonspanner = document.createElement("span");
buttoncontent = document.createTextNode(headerelement.innerHTML);
buttonspanner.appendChild(buttoncontent);
newbutton.appendChild(buttonspanner);
rightmenu.appendChild(newbutton);
});
}
The first part of the function deletes all the nodes which already are in the menu, in order to add the new ones when changing pages.
Trying to define newbutton.setAttribute() with onclick results in a SyntaxError (fields are not currently supported) in Firefox. It doesn't work if I set a static string as newbutton.setAttribute("onclick", "location.href=#headerpersonalinfo"); either.
Trying to set a static anchor link with newbutton.onclick set to a function, instead, works, such that
newbutton.onclick = function() {
location.href = "#headerpersonalinfo";
}
and this is pretty much how my current code is set up, except that I have given this function a unique variable, which I then call.
The problem I have is this, as I see it: The variable is redefined each time it finds a new header, so calling the function sends the user to the last header, and not the expected one. How can I set the function to be parsed at the moment I define onclick with it, and not call the function when the user presses the button?
PS: I'm using my own internal naming convention of files, headers, and items, in order to modularize my site as much as I can. Since this is a website only intended for my Curriculum Vitae, I'm its only developer.
The issue occurs because the you are hoisting "variables" to the global scope (newbutton and headerelement).
Set them to block scoped variables (const or let) and you will see that it works:
https://codesandbox.io/s/rm4ko35vnm
function loadMenues(file) {
var rightmenu = document.getElementById("right-menu");
while (rightmenu.firstChild) {
rightmenu.removeChild(rightmenu.firstChild);
}
[].forEach.call(document.getElementById(file).children, function(
custompaddingchild
) {
console.log(custompaddingchild);
const headerelement = custompaddingchild.getElementsByTagName("h1")[0];
console.log(headerelement.innerHTML);
const newbutton = document.createElement("div");
newbutton.setAttribute("class", "menu-item");
console.log(headerelement.id);
let movehere = function() {
location.href = "#" + headerelement.id;
console.log(headerelement.id);
};
newbutton.addEventListener('click', movehere);
const rightmenu = document.getElementById("right-menu");
const buttonspanner = document.createElement("span");
buttoncontent = document.createTextNode(headerelement.innerHTML);
buttonspanner.appendChild(buttoncontent);
newbutton.appendChild(buttonspanner);
rightmenu.appendChild(newbutton);
});
}
I'm in an AngularJS web project.
I would like to highlight a div when clicking on an anchor link. The structure is as follows:
<div interaction-list-item="" sfinx-interaction="interaction" class="ng-isolate-scope">
...
<a name="iid_7923"></a>
...
</div>
And the anchor link sets the location.hash to the similar upon clicking, so a URL could look like this: http://localhost:9000/#/home#iid_7923. This iid_ is dynamic, with different id's after the _
I've tried several jQuery solutions that ends up with really ugly and long code:
$(".indicator.active.line-D").click(function () {
// more similar code..
if ($("div:contains('D4')") && $("a:contains('D4')")) {
$(".col-md-6.interactionscol:contains('D4')").css("border", "3px solid #428bca");
setTimeout(function () {
$(".col-md-6.interactionscol:contains('D4')").css("border", "");
}, 1000);
}
// more similar code..
});
The purpose of this snippet is that upon clicking the anchor lnik, check for the div and anchor matching eachother and then apply CSS onto it, removing it after 1 second.
How could I do this smarter - if location.hash contains for example #iid_7923 and the div with a tag which name has the same, highlight it!
I just can't figure it out. Thanks in advance.
UPDATE: I would like to achieve similar to this: target selector
But my code for the anchor is not similar to the classical way.. it looks like this:
$scope.scrollToInteraction = function (iid) {
$location.hash(iid);
$anchorScroll();
};
Using angular, make your hash public in either a controller or for the whole application using the $rootScope:
angular.module('foo').run(['$location', '$rootScope', function($location, $rootScope) {
$rootScope.currentHash = function() {
return $location.hash();
};
}]);
And then in your html just use a directive to style your div:
<div data-ng-class="{'active': currentHash() == 'iid_7923'}">
Note the missing # in your currentHash().
You can use the onhashchange event to add a class to the parent element.
var lastParent = null;
window.addEventListener('hashchange', function() {
// Remove class from previous target parent
if(lastParent)
{
lastParent.className = (' '+lastParent.className+' ').replace(' hastarget ',' ');
lastParent = null;
}
// Remove the '#' from the location hash
var targetId = document.location.hash.substr(1);
var target = document.getElementById(targetId);
// Try to support the name attribute
if(!target)
{
var nameTargets = document.getElementsByName(targetId);
// If nothing found, don't do anything
if(nameTargets.length == 0) return;
target = nameTargets[0];
}
// If the element does not have any parent, add the class to the <html> tag
lastParent = target.parentElement || document.documentElement;
lastParent.className += ' hastarget';
}, false);
JSFiddle demo
I'am using jquery mobile 1.3.2 for my web project.
The following code creates a panel for all pages:
function injectPanelIntoAllPages(){
console.log("IncetPanel");
var panel = '<div data-role="panel" id="mypanel" data-position="left" data-display="push">' +
'<div><ul data-role="listview" id="history"></ul></div> </div>';
$(document).on('pagebeforecreate', '[data-role=page]', function () {
if ($(this).find('[data-role=panel]').length === 0) {
$('[data-role=header]').before(panel);
}
$(document).on('pagebeforeshow', '[data-role=page]', function () {
$(this).trigger('pagecreate');
});
});
}
Now i want to add (dynamically) list items to the listview in the panel, but it don't works.
For adding list items i use the following method:
function addToHistory(value) {
$("#history").append(
"<li id='history-element'>" + value + "</li>");
$("#history").listview("refresh");
}
What can i do to solve this issue?
Note that you're using same Id for both panel and listview. This isn't recommended, however, it still can work as long as you specify which element to target within active page.
Another note, you don't need to call any enhancement method once you append panels dynamically, since you append them on pagebeforecreate. They will be created/initialized by jQM on that event.
$(document).on('pagebeforecreate', function () {
if ($(this).find('[data-role=panel]').length === 0) {
$('[data-role=header]').before(panel);
}
});
To append elements into listview, you need to look for it into active page's. Otherwise, new elements will be added to first element with #history ID.
var listview = $.mobile.activePage.find("#history");
listview.append("elements").listview("refresh");
Demo
I'm generating a div dynamically and I've to check whether a dynamically generated div exists or not ? How can I do that?
Currently I'm using the following which does not detects the div generated dynamically. It only detects if there is already an element with the id contained in the HTML template.
$(function() {
var $mydiv = $("#liveGraph_id");
if ($mydiv.length){
alert("HHH");
}
});
How can I detect the dynamically generated div?
If mutation observes aren't an option due to their browser compatibility, you'll have to involve the code that's actually inserting the <div> into the document.
One options is to use a custom event as a pub/sub.
$(document).on('document_change', function () {
if (document.getElementById('liveGraph_id')) {
// do what you need here
}
});
// without a snippet to go on, assuming `.load()` for an example
$('#container').load('/path/to/content', function () {
$(this).trigger('document_change');
});
If it is added dinamically, you have to test again. Let's say, a click event
$("#element").click(function()
{
if($("#liveGraph_id").length)
alert("HHH");
});
How you inserting your dynamic generated div?
It works if you do it in following way:
var div = document.createElement('div');
div.id = 'liveGraph_id';
div.innerHTML = "i'm dynamic";
document.getElementsByTagName('body')[0].appendChild(div);
if ($(div).length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id').length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id_extra').length > 0) {
alert('exists'); //wont give alert because it doesn't exist.
}
jsfiddle.
Just for interest, you can also use a live collection for this (they are provided as part of the DOM). You can setup a collection of all divs in the page (this can be done in the head even before the body is loaded):
var allDivs = document.getElementsByTagName('div');
Any div with an id is available as a named property of the collection, so you can do:
if (allDivs.someId) {
// div with someId exists
}
If the ID isn't a valid identifier, or it's held in a variable, use square bracket notation. Some play code:
<button onclick="
alert(!!allDivs.newDiv);
">Check for div</button>
<button onclick="
var div = document.createElement('div');
div.id = 'newDiv';
document.body.appendChild(div);
">Add div</button>
Click the Check for div button and you'll get false. Add the div by clicking the Add div button and check again—you'll get true.
is very simple as that
if(document.getElementById("idname")){
//div exists
}
or
if(!document.getElementById("idname")){
// don't exists
}
I use this script to check if an anchor is within the URL. If found the showscroll function get called.
Only thing isn't working is the jump to the called anchor.
I'm new to JS - what is wrong with the function?
In the HTML page:
<script type="text/javascript">
<!--
function checkurl(){
if (window.location.href.match(/\#more/))
{
showscroll('more');
}
if (window.location.href.match(/\#tab2/))
{
showscroll('tab2');
}
}
//-->
</script>
</head>
<body onload="checkurl()">
.JS
function showscroll(id){
if (document.getElementById) {
var divid = document.getElementById(id);
divid.style.display = divid.style.display='block';
// NOT WORKING:
window.location.href = "#"+id;
//
return false;
} }
Edit: I can't use "scroll into view".
Instead of
window.location.href.match(/\#more/)
you can just do
window.location.hash == '#more'
and instead of assigning to the fragment, you can use the scrollIntoView method as described at https://developer.mozilla.org/en/DOM/element.scrollIntoView
Summary
The scrollIntoView() method scrolls the element into view.
Syntax
element.scrollIntoView(alignWithTop);
alignWithTop Optional
If true, the scrolled element is aligned with the top of the scroll area. If false, it is aligned with the bottom.
Note: By default, the element is scrolled to align with the top of the scroll area.