I "learned" JavaScript a few months ago but quickly picked up Python and spent the past few months writing programs in that language, so I decided it would be a good idea to go back and actually learn JavaScript. Right now I'm making a very simple "blog" with JS that takes the title of the post, generates a hash link from the post, and creates a recent posts section where you can click the link to jump to the post in the page.
For instance, say one of the posts is formatted like this:
<h2 class="post">Another post for you</h2>
<h4>I know you love these</h4>
With multiple posts, and an empty container at the bottom, which will be used to append the recent posts links:
<div id="get-post"></div>
My JS code basically grabs each title with the post class and creates a hash link from the element's title (removing spaces and commas). It then creates and appends a text node consisting of the post title, and then appends the entire link into the get-post container.
var postList = $('#get-post');
var post = $('.post');
function generateRecentPosts() {
post.each(function() {
// Create link from post title that will be used to
// access that post.
var postLink = document.createElement('a');
// Create text node from post title that will be appended
// to the postLink.
var text = document.createTextNode($(this).html());
// Add elements to the DOM.
postLink.href = createLocalLink($(this));
postLink.appendChild(text);
postList.append(postLink);
postList.append('<br />');
});
}
function createLocalLink(elm) {
// Creates the href link that will be used to go to a blog post.
// For example, if the title of the elm parameter is "My Post",
// a link is created called #My-Post that will be used to access
// that post.
elm.id = elm.html().replace(/,/g, '').replace(/\s/g, '-');
console.log(elm.id); // Make sure the ID is added.
return '#' + elm.id;
}
generateRecentPosts();
My problem is that the links it generates to not point to the ID created for each title. When I click on the link, I can see that it successfully created the href hash #My-Post and added it to the anchor tag, but it doesn't take me to the post title.
Example: http://jsfiddle.net/samrap/GQtxL/
I even added a console log function to make sure the ID is being added to the title as I thought that was the problem, but it isn't because the console is printing the correct new ID. I could really use some help in figuring out where exactly the problem is here.
Your h2 tags need to have an id or name attribute that corresponds with the link, that is what makes internal links work. The id is not getting added because you are accessing a jQuery object as if it were a DOM node (elm.id = ...). Modify your createLocalLink function to use jQuery's attr method to set the id property:
elm.attr('id', elm.html().replace(/,/g, '').replace(/\s/g, '-'));
Additionally, since you have jQuery available you could whittle your code down to:
var $this = $(this),
link = createLocalLink($this);
var $postLink = $('a', {
text: $this.text(),
href: link
})
postList.append($postLink).append('<br />');
Here is your fiddle updated: http://jsfiddle.net/GQtxL/1/
This is because your link uses the href = "#My-Post" but none of the posts has the ID "My-Post". It only has a class "post".
This happens because the argument that your are passing to the createLocalLink() function is a DOM Node. But by doing elm.id you are not changing the DOM property but adding another property to the "elm" object. Thus your "elm" object is
x.fn.x.init[1]
0: h2.post
context: h2.post
id: "Another-post-for-you"
length: 1
__proto__: Object[0]
Thus the actual post never gets the attribute ID only "elm" object gets it. Note the empty ID attribute below
draggable: false
firstChild: text
firstElementChild: null
hidden: false
id: ""
innerHTML: "Another post for you"
innerText: "Another post for you"
Thus your document has no element with the ID "My-Post". You can view the source of your HTML to verify this.
For internal links to work there should be an element with the same ID as that used in the href attribute of the link.
For example
<div id="post1">
Your Post Here
</div>
<!--just to show the effect of moving to the post-->
<div style="clear:both; height:900px"></div>
Click Here
This would work because there is an element with the id "post1" and the link uses the href "#post1" which links it to the corresponding element. Hence, add the corresponding id to your post as well (other than your link) for it to work.
In function createLocalLink you are using elm argument as dom node, but actually passing a jQuery wrapped object to it, which don't have id property. To get it work, use elm.get(0).id = ... or elm.attr('id', elm.text().replace(/,/g, '').replace(/\s/g, '-'););
Related
Background description:
I am tracking clicks on links on a web page using Google Tag Manager (GTM) and have set this up successfully, together with python code to extract the data from the API. However, GTM currently doesn't return any indication of the position on the page of the link clicked. I would like to put in the Event Label the position in the DOM of the clicked element.
The purpose of doing this is twofold: Firstly, so I can distinguish identical links (i.e. links which have the same link text and which go to same destination). Secondly, so that I can identify which of the many sections of the page the link is in: is it in the sidebar, on the top bar, in the main content etc.
Problem
I have tried using the {{Click Element}} variable, but this only returns the href of the link, not the position on the DOM.
This is puzzling because when I go into Preview mode in GTM and have a look at the data layer, I see very clearly that there was a push API call to send the DOM location:
dataLayer.push({
event: 'gtm.click',
gtm.element: 'https:// [rest of URL] : html.js.yes-js.js_active >
[lots more DOM elements separated with >s of which I am only including a few]
> div#page-container > div#et-main-area > div#main-content > h3.rpwe-title > a',
gtm.elementClasses: '',
gtm.elementId: '',
gtm.elementTarget: '',
gtm.elementUrl: __*~~URL~~*__,
gtm.uniqueEventId: 425
})
And in the "Variables" tab of the GTM preview page, Click Element shows up just as above: it is a Data Layer Variable, it is a string, and its value is given as first the URL, then a colon, followed by the long description of where the link is on the DOM, with all the parents starting from the root of the document, all the way down until the clicked link.
So why, when I add the {{Click Element}} variable to the GTM Event Label, does this only return the href of the link, not the position on the DOM? I submit the changes and publish a new version in GTM, then go to Google Analytics, and only the link href shows there.
What I have tried
Going into the DevTools in chrome (right click, Inspect) and entering the console and typing dataLayer shows that some events, e.g. gtm.elementVisibility, do have a gtm.element object which seems pretty vast. In this gtm.element object, you can click on parentElement which then has its own parentElement and so on until the top level of the DOM. So this data is clearly all there.
To access it I tried a Custom JS variable in GTM which used JSON.stringify to convert Click Element into a string. This didn't work, I suspect because the gtm.element object is too complex, with nested objects and circular references to many locations within the object.
I don't know Javascript, I am groping in the dark with it, I just want to get a nice string through to Google Analytics and from there to my python code where I can manipulate it as necessary.
Possible solution which isn't practical
In GTM I could make multiple triggers for the same event, and specify for each trigger that Click Element matches the CSS Selector for each of the sections of the page. However that would require a separate trigger for each section, which would get messy if I ever need to update the trigger settings. It also wouldn't help me distinguish between identical links.
Question
Why isn't the above working nicely, and how can I accomplish this (preferably with minimal javascript coding...)? Thanks!
Simo Ahava has a great blog post about exactly this question, at https://www.simoahava.com/analytics/create-css-path-variable-for-click-element/ (no idea why multiple google searches didn't find this...)
As suspected in the question, he explains that Click Element is not actually a string with the location of the link in the DOM, as the GTM Preview mode indicated. It is a complex HTML element.
He goes on to provide javascript code which takes this complex Click Element and extracts the location in the DOM of the link:
function() {
// copied from https://www.simoahava.com/analytics/create-css-path-variable-for-click-element/
// Build a CSS path for the clicked element
var originalEl = {{Click Element}};
var el = originalEl;
if (el instanceof Node) {
// Build the list of elements along the path
var elList = [];
do {
if (el instanceof Element) {
var classString = el.classList ? [].slice.call(el.classList).join('.') : '';
var elementName = (el.tagName ? el.tagName.toLowerCase() : '') +
(classString ? '.' + classString : '') +
(el.id ? '#' + el.id : '');
if (elementName) elList.unshift(elementName);
}
el = el.parentNode
} while (el != null);
// Get the stringified element object name
var objString = originalEl.toString().match(/\[object (\w+)\]/);
var elementType = objString ? objString[1] : originalEl.toString();
var cssString = elList.join(' > ');
// Return the CSS path as a string, prefixed with the element object name
return cssString ? elementType + ': ' + cssString : elementType;
}
}
This returns something looking like 'HTMLDivElement: html > body > div#blog > div.hasCoverMetaIn#main' where div is the type of element, element class(es) follows the period (.), and element id follows the hash (#).
So thank you to Simo Ahava, hope it is OK to share his code here. See his article for fuller explanation
I am learning javascript and trying to build a chat app like intercom.
How do i go about creating a popup on another page once my js script is planted??
I do it locally like so:
function Hide()
{
document.getElementById('div1').style.visibility="hidden";
}
There is many way to do it i'll explain the idea with some examples, let's go
Our code based on two functionalities:
1: innerHtml = "<YOUR CODE/>"; This property is for injecting the html in the element more info.
2: document.getElementById("IdName") This property is for selecting and element wich we will apply some functionalities, in our case is the property N°1 more info.
3: <div id="IdName"></div> Here where we will append our html or text more info.
Now we start with some examples:
1st example:
API File:
function function_name(argument) {
document.getElementById(argument).innerHTML = "<p>Paragraph example..</p>";
}
User File:
// first of all the user need to put a div with an attribute ID in his html where
//he want to append the html given by the API
<div id="IdName"></div>
//after that he must call the specified function wich is in our case function_name() and put the ID as argument
function_name("IdName"); // this will append the html in the div with the ID == IdName
Also you can use document.getElementsByClassName("className"); in place of ID
2nd example:
In this case the user don't need to put any additional html or any other things; in this example we will add our html into the body element wich is a necessary element in HTML page.
document.body.innerHTML += "<p>Paragraph example..</p>";
I'm trying to use JavaScript to create an ID for my links and also to tell it where to link to.
My JavaScript has generated a link element in my HTML:
<a id = "NB4-CAXL-14U-12-AAG"> Link Text </a>
And that appears as it should.
I then have a variable eopartnum[i]:
console.log(eopartnum[i]); //output: NB4-CAXL-14U-12-AAG
This variable matches my ID for my link above. Then i tried to access that link via the ID and assign an href to it, like so:
var linktoprod = document.getElementById(eopartnum[i]);
console.log(linktoprod); //returns null
linktoprod.href = "http://www.enviroptics.com/"; //Cannot set property 'href' of null(…)
Why does my linktoprod come up as null? Is my syntax wrong?
JSfiddle for full code: http://jsfiddle.net/98oL12tk/17/ Lines 106-109 in JS section.
The problem is that you are calling getElementById() before you append the table to the document. At the time that you are querying for the ID, it doesn't yet exist. This example seems a bit contrived; I think you could just set firstcelllink.href = 'http://www.enviroptics.com/';
EDIT: probably more appropriate to use firstcelllink.setAttribute('href', 'http://www.enviroptics.com/');
I'm trying to add a search link to an online form with a userscript using jQuery. I don't work too much in firefox and I feel like things that would normally work in chrome don't in ff 9/10 times for me. But anyway... this needs to be with ff.
I'm taking the text from a <p> element and creating a search url out of it (or trying to). Right now this is the function I'm trying that should be doing it... but it's doing nothing, not even any errors in console
$(function() {
var companyName = $('p')[7]; // Element that contains the name text
var companyText = companyName.text(); // Retrieve the text from element
var mixRankUrl = $("<a></a>").innerHTML("Search Mixrank"); // Create an <a> element
mixRankUrl.href = 'https://mixrank.com/appstore/sdks?search=' + companyText; // Define the href of the a element
var sdkPara = $('label.control-label')[10]; // Where I want it to go
sdkPara.append(mixRankUrl); // Append the element
});
Also, whoever wrote the html uses hardly any ids, and most classes are assigned to 10 or more elements... so unless there's a better way, I'm sort of stuck using node selectors (which stay the same form to form).
The problem is that you try to use jQuery method on DOM element. Don't understand why you don't have any errors with your code.
For exemple : $('p')[7] return a DOM element while $('p').eq(7) return a JQuery object. So you can't use a jQuery method like text() on your DOM element. You need to deal with jQuery object.
For the same reason, you had a problem with the declaration of your label object and with the modification of the href attribute of your link.
Try like this :
$(function() {
var companyName = $('p').eq(7); // Element that contains the name text
var companyText = companyName.text(); // Retrieve the text from element
var sdkPara = $('label.control-label').eq(10); // Where I want it to go
var mixRankUrl = $('<a>',{
text: 'Search Mixrank',
href: 'https://mixrank.com/appstore/sdks?search=' + companyText
}).appendTo(sdkPara); // Append the element
});
Essentially, I want to pull text within a div tag from a document on my server to place it in the current document. To explain the reason: I want to pull a headline from a "news article" to use it as the text for a link to that article.
For example, within the target HTML is the tag:
<div id='news-header'>Big Day in Wonderland</div>
So in my current document I want to use javascript to set the text within my anchor tags to that headline, i.e.:
<a href='index.php?link=to_page'>Big Day in Wonderland</a>
I'm having trouble figuring out how to access the non-current document in JS.
Thanks in advance for your help.
ADDED: Firefox style issue (see comment below).
I'm not sure where you're getting your HTML but, assuming you already have it in a string, you could create a document of your own, stuff your HTML into it, and then use the standard getElementById to pull out the piece you want. For example:
var doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
doc.documentElement.innerHTML = '<body><div>Nonsense</div><div id="news-header">Big Day in Wonderland</div><p>pancakes</p></body>';
var h = doc.getElementById('news-header');
// And now use `h` like any other DOM object.
Live version: http://jsfiddle.net/ambiguous/ZZq2z/1/
Normally, I would try to solve an issue only with the tools specified by the user; but if you are using javascript, there really is no good reason not to just use jQuery.
<a id='mylink' href='url_of_new_article' linked_div='id_of_title'></a>
$(function() {
var a = $('#mylink');
a.load(a.attr('href') + ' #' + a.attr('linked_div'));
});
That little function up there can help you update all your link's text dynamically. If you have more than one, you can just put it in a $('a').each() loop and call it a day.
update to support multiple links on condition:
$(function() {
$('a[linked_div]').each(function() {
var a = $(this);
a.load(a.attr('href') + ' #' + a.attr('linked_div'));
});
});
The selector makes sure that only the links with the existence of the attribute 'linked_div' will be processed.
You need to pull the content of the remote document into the current DOM, as QuentinUK mentioned. I'd recommend something like jQuery's .load() method