I am dynamically creating javascript and attaching it to the onclick event of links on my page using $(document).ready()
My onclick javascript is used to generate event functions that I am passing to Google Analytics to track events on my page, such as clicks on banners and downloaded PDFs. I am getting stats in Google Analytics for these events from every browser except for IE. So, something is wrong with my code in IE (I have searched and searched for errors on my page, there are none).
Normally I would just do something like $("a").click ... do stuff ... but for whatever reason, the only way I could get the Google Analytics event tracking to work was by putting the tracking event function directly on my links. So I'm using the following code to inject the tracking event function into my link's onclick once the page loads....
// Tracks favorites on the home page.
$("._gatHomePageFavorites").each
(
function(index)
{
var description = "Content ID: " + getParameterNamedID($(this).attr("href")) + " - " + $(this).children().first().attr("alt");
$(this).attr("onclick","alert('1');_gaq.push(['_trackEvent', 'Favorites - Home Page', 'Icon Click','" + _gatCleanString(description) + "']);alert('2');");
}
);
I think my problem is that IE is not putting my code on the onclick. But I don't know of a good way to view the generated source in IE. I have tried a couple of javascript functions in the address bar to bring up the generated source, assuming they work, then my code is not injecting the tracking event function into my link's onclick for IE. I see the tracking event function in the onclick in Firefox's view generated source.
As another test, you can see I added alerts around my tracking event funciton. In FF both alerts trigger, In IE neither alert triggers.
One more piece of info. My Google Analytics is not recording events for any IE browser. As far as I can tell, my issue is not specific to one version of IE.
How can I tell if my dynamic javascript is getting into the onclick for IE, and then what can I do to get it into the onclick for IE?
UPDATE
To simplify the problem and to focus the direction of the answers, I removed the Google Analytics event function. Now, all I am doing is injecting alert() into the onlick. IE won't even trigger the alert(). I have tried the following...
// Tracks favorites on the home page.
$("._gatHomePageFavorites").each
(
function(index)
{
$(this).attr("onclick","alert('1')");
}
);
and
// Tracks favorites on the home page.
$("._gatHomePageFavorites").each
(
function(index)
{
$(this).attr("onclick","setTimeout(\"alert('1')\", 1000);return false");
}
);
So I'm still leaning towards my javascript is not being injected into the onclick in IE.
What is the most reliable way to view generated source in IE?
If I can confirm that my code is not being injected into the onclick attribute of the link, then I can at least have an answer as to why Google Analytics isn't tracking events for IE. It would be because my injected code does not exist in IE.
You should not be adding the 'onclick' attr, but rather using this using jQuery .click() event.
function(index){
var description = "Content ID: " + getParameterNamedID($(this).attr("href")) + " - " + $(this).children().first().attr("alt");
$(this).click(function() {
alert('1');
_gaq.push(['_trackEvent', 'Favorites - Home Page', 'Icon Click', _gatCleanString(description)]);
alert('2');
});
}
something like above, sorry wrote this quick, so might have a typo.
Slim chance, but if you have any VBScript on your page then you should prepend your onclick string with "javascript:"
You could just use the time-honoured DOM0 onclick property, though there's really no decent reason why jQuery's click() method wouldn't work.
$("._gatHomePageFavorites").each
(
function(index)
{
var $this = $(this);
var description = "Content ID: "
+ getParameterNamedID($this.attr("href")) + " - "
+ $this.children().first().attr("alt");
this.onclick = function() {
alert('1');
_gaq.push(['_trackEvent', 'Favorites - Home Page', 'Icon Click',
_gatCleanString(description)]);
alert('2');
};
}
);
jQuery's attr() method is generally not useful, but that's a whole different rant.
Something to be aware of tracking links is that if the browser leaves the page before the tracking pixel is fetched, the event may not be recorded, depending on the browser, computer, & network speed. I've had good luck with the following (modified from #Tim Down's code):
$("._gatHomePageFavorites").each
(
function(index)
{
var $this = $(this);
var description = "Content ID: "
+ getParameterNamedID($this.attr("href")) + " - "
+ $this.children().first().attr("alt");
$this.click(function(e) {
alert('1');
_gaq.push(['_trackEvent', 'Favorites - Home Page', 'Icon Click',
_gatCleanString(description)]);
if ($this.attr('target') != '_blank') {
e.preventDefault();
setTimeout('document.location = "' + $this.attr('href') + '"', 150);
}
});
}
);
Essentially, if the link isn't opening in a new window, wait and follow it ourselves.
It turns out that my problem had nothing to do with Google Analytics or it's tracking event. After a lot of testing, I finally determined that in IE, jQuery's $().attr() was not working.
The odd thing was that it didn't break or throw an error. IE just ignored it somehow and would not add my dynamic javascript to the onclick parameter of the anchor tag.
Solutions...
The obvious one is to bind to the event like everyone suggested. If you can use $().click() then I agree, use it, always. Never use $().attr("onclick","do something");
However other circumstances in my project prevented me from using $().click(). I was unable to get stats into Google Analytics using it's event tracking function unless the event tracking function was inline on the anchor tag.
Went old school...
$(".obj").each
(
function (index) {
this.setAttribute("onclick", "alert('It is Working');");
}
);
Thanks for everyone's help.
Related
I've been trying out the excellent Medium Editor. The problem that I've been having is that I can't seem to get links to "work".
At the simplest, here's some HTML/JS to use to demonstrate the problem:
HTML:
<html>
<head>
<script src="//cdn.jsdelivr.net/medium-editor/latest/js/medium-editor.min.js"></script>
<link rel="stylesheet" href="//cdn.jsdelivr.net/medium-editor/latest/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/medium-editor/latest/css/themes/beagle.min.css" type="text/css">
</head>
<body>
<div class='editable'>
Hello world. link
</div>
</body>
</html>
Javascript:
var editor = new MediumEditor('.editable');
This fiddle demonstrates the problem (using the code above).
If you hover on the link, a popup appears.
If you click the link, nothing happens.
If you click the popup, a form appears where you can edit the link.
It seems to me that clicking the link should take me wherever the link's href is targeting. The only way to use the link is to right click and either open in a new tab or new window -- which I don't want to ask my users to do.
I feel like I must be missing something simple in the configuration (either the Anchor Preview Options or the Anchor Form Options). Unfortunately, I'm not seeing it.
In my actual application, I'm not using jQuery, but I am using angularjs. If a strictly Medium Editor answer doesn't exist, I can fall back to using basic JS or anything that angularjs provides.
I've found how to bind event.
Here is full event list https://github.com/yabwe/medium-editor/blob/master/CUSTOM-EVENTS.md
Try to change your code to
var editor = new MediumEditor('.editable')
.subscribe("editableClick", function(e){if (e.target.href) {window.open(e.target.href)}})
https://jsfiddle.net/fhr18gm1/
So medium-editor is built on top of the built-in browser support for contenteditable elements. When you instantiate medium-editor, it will add the contenteditable=true attribute to whatever element(s) you provided it.
By default, since the text is now editable (the contenteditable attribute makes the browser treat it as WYSIWYG text) the browser no longer supports clicking on the links to navigate. So, medium-editor is not blocking these link clicks from happening, the browsers do it inherently as part of making the text editable.
medium-editor has built in extensions for interacting with links:
anchor extension
allows for adding/removing links
anchor-preview extension
shows a tooltip when hovering a link
when the tooltip is clicked, allows for editing the href of the link via the anchor extension
I think the underlying goal of the editor is the misunderstanding here. The editor allows for editing text, and in order to add/remove/update links, you need to be able to click into it without automatically navigating away. This is what I think of as 'edit' mode.
However, the html produced as a result of editing is valid html, and if you take that html and put it inside an element that does NOT have the contenteditable=true attribute, everything will work as expected. I think of this as 'publish mode'
I look at editors like word or google docs, and you see a similar kind of behavior where when you edit the document, the links don't just navigate away when you click on them, you have to actually choose to navigate them through a separate action after you click the link. However, on a 'published' version of the document, clicking the link will actually open a browser window and navigate there.
I think this does make for a good suggestion as an enhancement to the existing anchor-preview extension. Perhaps the tooltip that appears when hovering a link could have multiple options in it (ie Edit Link | Remove Link | Navigate to URL).
tldr;
Links are not navigable on click when 'editing' text in a browser via the built-in WYSIWYG support (contenteditable). When not in 'edit' mode, the links will work as expected.
This could make for a nice enhancement to the medium-editor anchor-preview extension.
Working off some ideas from #Valijon in the comments, I was able to get it to work using the following code:
var iElement = angular.element(mediumEditorElement);
iElement.on('click', function(event) {
if (
event.target && event.target.tagName == 'A' &&
event.target.href && !event.defaultPrevented) {
$window.open(event.target.href, '_blank');
}
});
I think the key is that apparently the editor lets the event propogate to the ancestor elements, so I was able to just listen for the click on the top level editor element.
Here, $window is angular's $window service -- If you're not using angularjs, window would do the trick and I used angular.element to ease the event listener registry, but you could do it the old-fashioned way (or using the JS framework of your choice).
What I really wanted when I asked the question was behavior similar to Google Docs when in "edit" mode (as described by Nate Mielnik). I opened an issue on the Medium Editor tracker and they decided not to implement it as part of the core medium editor, but they noted that they would be happy to have someone add that functionality as an extension.
So, I decided to implement that functionality as an extension as suggested. It can be found as part of MediumTools1. The project is still in very early stages (e.g. I haven't done anything to make the styling look better, or to use better minifying practices, etc. but we'll happily accept Pull Requests for that).
The guts of the code look like this:
var ClassName = {
INNER: 'medium-editor-toolbar-anchor-preview-inner',
INNER_CHANGE: 'medium-editor-toolbar-anchor-preview-inner-change',
INNER_REMOVE: 'medium-editor-toolbar-anchor-preview-inner-remove'
}
var AnchorPreview = MediumEditor.extensions.anchorPreview;
GdocMediumAnchorPreview = MediumEditor.Extension.extend.call(
AnchorPreview, {
/** #override */
getTemplate: function () {
return '<div class="medium-editor-toolbar-anchor-preview">' +
' <a class="' + ClassName.INNER + '"></a>' +
' -' +
' <a class="' + ClassName.INNER_CHANGE + '">Change</a>' +
' |' +
' <a class="' + ClassName.INNER_REMOVE + '">Remove</a>' +
'</div>';
},
/** #override */
createPreview: function () {
var el = this.document.createElement('div');
el.id = 'medium-editor-anchor-preview-' + this.getEditorId();
el.className = 'medium-editor-anchor-preview';
el.innerHTML = this.getTemplate();
var targetBlank =
this.getEditorOption('targetBlank') ||
this.getEditorOption('gdocAnchorTargetBlank');
if (targetBlank) {
el.querySelector('.' + ClassName.INNER).target = '_blank';
}
var changeEl = el.querySelector('.' + ClassName.INNER_CHANGE);
this.on(changeEl, 'click', this.handleClick.bind(this));
var unlinkEl = el.querySelector('.' + ClassName.INNER_REMOVE);
this.on(unlinkEl, 'click', this.handleUnlink.bind(this));
return el;
},
/** Unlink the currently active anchor. */
handleUnlink: function() {
var activeAnchor = this.activeAnchor;
if (activeAnchor) {
this.activeAnchor.outerHTML = this.activeAnchor.innerHTML;
this.hidePreview();
}
}
});
As an explanation, I just use medium's flavor of prototypical inheritance to "subclass" the original/builtin AnchorPreview extension. I override the getTemplate method to add the additional links into the markup. Then I borrowed a lot from the base implementation of getPreview, but I bound new actions to each of the links as appropriate. Finally, I needed to have an action for "unlinking" the link when "Remove" is clicked, so I added a method for that. The unlink method could probably be done a little better using contenteditable magic (to make sure that it is part of the browser's undo stack), but I didn't spend the time to figure that out (though it would make a good Pull Request for anyone interested :-).
1Currently, it's the only part, but I hope that'll change at some point. . .
I want to place a button on CRM 2011 form.
function create_button(fldName, btnLabel, btnWidth, evt)
{
try{
fldName = "inmate_button_submit";
btnLable="Click Me";
// btnWidth="200px";
var btn = '<button class="ms-crm-Button" onclick="evt()" style="width:50px" id="' + fldName + '" onmouseover="Mscrm.ButtonUtils.hoverOn(this);" onmouseout="Mscrm.ButtonUtils.hoverOff(this);" >Click Me</button>';
var ctrl = null;
try {
ctrl = Xrm.Page.ui.controls.get(fldName).get_chromeElement()[0];
} catch (e) {
ctrl = Xrm.Page.ui.controls.get(fldName)._control.get_element();
}
// Add the new button
ctrl.innerHTML += btn;
// Hide the textbox
ctrl.children[0].style.display = 'none';
ctrl.children[1].style.display = 'none';
// Hide the label
Xrm.Page.ui.controls.get(fldName).setLabel(btnLable);
// Add Event to the newly created button
ctrl.children[0].attachEvent('onclick', evt);
}
catch(e){alert(e.description);}
}
function evt()
{
alert("You have clicked me!!");
}
The above is my following code which places the button on the form. When i click on the button, after showing the alert crm gives me the following error.
ERROR
An error has occurred.
Try this action again. If the problem continues, check the Microsoft Dynamics CRM Community or you for solutions or contact....
I have no idea why this is happening. Any help guys?
Keep in mind that using getElementById is going to be unsupported and may not work (does not work in Outlook 2007) in some browsers.
I would recommend placing this is in a web resource, or utilizing the ribbon for this functionality. Would either of those meet your requirements?
If you use your js as a webresource then you shouldnt have any problems.
Or you can even trigger the function OnLoad
Please see following :
http://www.mscrmconsultant.com/2012/07/insert-custom-button-on-crm-form-using.html
i will recommend add custom webresource ( HTML page which contanis javascript functionality on in onload event ) if you need access to form, use window.parent.document.Xrm.Page ....
2 things might cause this issue:
evt function is not accessible to your button
Resolution: try registering the evt function in global scope i.e.
evt = function() { alert("…"); }
or
window.evt = function() {}
2. Your button is using the same field name as the placeholder field.
This might cause internal issues.
Resolution: Try giving your button another (bogus) id instead i.e. fieldname + "_button"
Have you tried the 3rd party applications...
http://crmvisualribbonedit.codeplex.com/
Call the function from a web resource.
NOTE: Remember to add $ to reference the web resource location
Example $webresource:ButtonScript.js
I am trying to use jQuery to create a some custom clickable menu, the final product works fine everywhere else except in IE8... When I click on the link, nothing happen. However, if i open the debugger, and refresh the onclick attribute, then it works fine afterward in IE. So it seems like IE, didn't "see" the onclick created by jQuery? Could that be possible?
Here is some sample code:
var props;
props['views'] = [ 'item1', 'item2', 'item3' ];
saving the onclick from another link and transfer it to the menu
props['onclick'][i] = $(this).closest('a').attr('onclick');
then later on
for (var i in props.views) {
var a = $('<a></a>');
// override the class from props.linkclass
var cssclass = 'myMenu';
// override the onclick from props.onclick[i]
var onclick = props.onclick[i] + ';highlightDynamicMenu(this);';
a.attr( {
'class' : cssclass,
'href' : 'javascript:void(0);',
'onclick' : onclick }
);
a.append(props.views[i]); // name of the link
menu.append(a);
}
This is the link that gets generated from my code, again, works perfectly fine everywhere else except IE8... ugh.
<a onclick="javascript:showMyDiv('div1208', 'div1208', event);highlightDynamicMenu(this);" class="myMenu" href="javascript:void(0);">item1</a>
Now, as I was mentioning before, if I open the debugger, and refresh the link, say removing "javascript:" and hit enter, then IE8 would "see" the link...
What exactly is the issue here? >.<
Update: I tried using: a[0].setAttribute('onclick',onclick); IE8 still won't pick it up...
You should not manipulate the onclick attribte in this way. Inline handlers are in general a bad idea, so hacking around with them like this is even worse.
Instead, you should use event handlers. In this case:
a.click(highlightDynamicMenu);
You can keep attr... 'onclick':props.onclick[i], since it looks like you're passing a string, but really you should try to make that an anonymous function and pass it through.
No Issue in code by Defualt most of times IE behaves differently than others.
Similar issue reported on msdn.
http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/ec196223-248b-4483-ada8-93838f5c5249/
Try like this
Assuming props.onclick[i] sarts with javascritp: as per your example onclick="javascript:show('div1208', 'div1208', event);highlightDynamicMenu(this);"
var onclick = props.onclick[i] + ';highlightDynamicMenu(this);';
a.attr( {
'class' : cssclass,
'href' : onclick, // On Click variable value which will be something like javascript:show('div1208', 'div1208', event);highlightDynamicMenu(this);
}
);
a.append(props.views[i]);
Quite a simple question, yet it has been bugging me all week!
Firstly, I do not expect someone to write me this huge piece of code, then me take it away and claim it for my own. Would prefer someone to actually help me write this :)
I am attempting to show a playlist on my website as a png image.
I have 2 playlists that must be shown.
The playlist will change on an image press.
I have 4 button images, 'CD1up', 'CD1down', 'CD2up' and 'CD2down'.
I would like to have these buttons changing what current playlist is being shown, but also showing the buttons correct state. For example, is playlist1 is being shown, then 'CD1up' must be shown, and 'CD2down' shown.
I would post my current code here, but I basically scrapped it all and decided to start from scratch since I'm terrible with web javascript.
All help is greatly appreciated!
I can basically fluent in HTML and CSS, but horrible at web javascript.
Some notes:
If you give each image an id attribute, you can use document.getElementById to get a reference to that element once the page is loaded.
Then you can set the src property on that element to a new URL to change the image.
Make sure your script tag is after the elements in the HTML (just before the closing </body> works) so that the elements exist when you want them.
You can add a click event handler to any element on the page. Most browsers support addEventListener but some older versions of IE still require you to use attachEvent to hook up the handler. So you see people with functions that look something like this:
function hookEvent(element, eventName, handler) {
if (element.addEventListener) {
element.addEventListener(eventName, handler, false);
}
else if (element.attachEvent) {
element.attachEvent("on" + eventName, handler);
}
else {
element["on" + eventName] = function(event) {
return handler.call(this, event || window.event);
};
}
}
So for example, if you have this img:
<img id="myImage" src="/path/to/img.png">
This cycles through four images on click:
<!-- This must be AFTER the `img` above in the HTML,
just before your closing /body tag is good -->
<script>
(function() {
var myImage = document.getElementById("myImage"),
images = [
"/path/to/img1.png",
"/path/to/img2.png",
"/path/to/img3.png",
"/path/to/img4.png"
],
index = -1;
hookEvent(myImage, "click", imageClick);
function imageClick() {
++index;
if (index >= images.length) {
index = 0;
}
myImage.src = images[index];
}
})();
</script>
You can get a lot of utility functionality and smooth over browser differences using a decent library like jQuery, YUI, Closure, or any of several others, although if all you want to do on the page is change the images sometimes and handle a click or two, that might be overkill.
I am trying to track the outbound links via google analytics, and Google suggests using this:
<script type="text/javascript">
function recordOutboundLink(link, category, action) {
_gat._getTrackerByName()._trackEvent(category, action);
setTimeout('document.location = "' + link.href + '"', 100);
}
</script>
Which is fine, except, my outbound links are to be opened in a new tab, and I am (naturally) using a target="_blank" for that..
but, the setTimeout method takes that away, and opens the link in the same page..
I've tried using window.open() but I am worried that it will be blocked by browsers..
So, is there anyway that I can execute this js function, and delay the click for just a little while? (100ms as google suggests)?
Thanks.
I've looked at other questions like this on SO, but they don't deal with opening in new tab/window.
Ok to evolve the answer above here is a Jquery plugin that can provide listen a selection of links (based on your own criteria) and provide you a method for callback to them.
fiddle
So in the OP's case the setup could look like:
Google
$(document).ready(function() {
$('a').trackOutBound(null,function() {
var category= $(this).data('category');
_gat._getTrackerByName()._trackEvent(category, $(this).attr('href'));
});
});
Simple, just remove the setTimeout() part of it. So all it does is call the _trackEvent function.
Your links should execute both the javascript function and open the new window, if you just keep them something like:
Click here
<script type="text/javascript">
function recordOutboundLink(category, action) {
_gat._getTrackerByName()._trackEvent(category, action);
}
</script>
I use this to keep the function waiting before continuing with the default browser behavior:
var wait_until = new Date().getTime() + 500;
while (new Date().getTime() < wait_until) {
//Do nothing, wait
}