GTM fire event before page act, how? - javascript

I have a simple page, which in URL https://www.myshop.com/user/quickact, and the html looks like :
<input id="pid" />Keyin Product ID
<input id="count" />Keyin product count
<a id="addList" href="javascript:void(0);" class="buttonAction">Add to List</a>
<!--some external js file handle click event for this link-->
When user clicked hyper text [Add to List], my page will :
Get pid/count value, put into a javascript array.
Reset pid with '', reset count with 1'.
Things I'm now doing in GTM are :
When PageURL contains "user/quickact"
And user clicked link with ID "addList"
Get pid/count value, and send them into GA via GTM tag.
Here's how I read them in GTM's custom variable
function()
{
var pid=document.getElementById('pid').value;
var count=document.getElementById('count').value;
return pid+','+count;
}
My problem is, GA event did fired, but the value...my custom variable always return ',1'.
It means my GTM tag fired after page's action, so it can only read reset value, not the actual value user key-in.
Can any one gives suggestion to solve this ?

I'm not sure if there's a solution to control the order of execution of multiple events, but one workaround would be to provide the required data for GTM with the same functionality, that you are using to get the values and to reset them. This assumes, that you have control over this code.
You could do something like this:
function yourFunctionForButtonClick() {
//Your code to get pid/count value, put into a javascript array.
//new code to provide data to GTM
dataLayer.push({
event: 'newPidProvided',
pidcountvalue: pid + ',' + count
});
//Your code to reset pid with '', reset count with 1'.
}
In this case, you need to set up your GTM trigger to listen to newPidProvided event instead of clicks, while still checking for "user/quickact" to be present in the URL. (Which could also be done in the function, if no other tag or trigger uses pid+count in GTM on other pages.) You'll also have to use a dataLayer variable instead of custom JavaScript type.

Related

Dynamically loaded JS needs to be clickable just like it's in the html

My page fires off an ajax query, where the MySQL Db is queried and the results are returned. (all successful).
Those results are formatted for output as a shopping gallery/catalogue and also as an accordion filter menu. So I can filter the shopping catalogue display. eg say I want to see only items that are red.
All is working so far.
My problem is with the filter accordion menu - dynamically created in js.
When I click on any selectable item in the tab-content, nothing happens. This means the parameter that should be sent, isn't being sent.
If I hard code the accordion filter or even load it with my server-side language, into the html directly, the filtering does send off the parameter and so the shopping catalogue is adjusted accordingly but, in that scenario, I am unable to dynamically change the filter menu.
I think the code I shall post below is the relevant code that recognises changes in the originally loaded content and fires off the ajax but (I think) it doesn't understand any changes to textboxes in the dynamically loaded content.
Please help me to understand what I need to add that will make dynamically loaded content fire-off to the ajax calls.
var $checkboxes = $("input:checkbox");
function update_nav_filter(opts) {
$.ajax({
type: "POST",
url: "/php-queries/product-filter-query.php",
dataType: 'json',
cache: false,
data: {
filterOpts: opts
},
success: function(records) {
//console.log(records);
//alert('SUCCESS!');
// alert(records);
$('#filters_div').html(makeFilter(records));
}
});
}
$checkboxes.on("change", function() {
//alert('there is a change is checkbox status'); // working on page load but not when any checkbox is clicked-on
var opts = getCatalogueFilterOptions();
updateCatalogue(opts);
update_nav_filter(opts);
});
$checkboxes.trigger("change");
Any help greatly appreciated.
I have created an event listener.
Following page-load, I select an item in the JS generated nav filter. eg pedal_bins in the sub_category section. I am then shown a display of pedal_bins. :)
Then I select 'kettles', another sub_category but I can only see the last sub_category that I click on. The pedal_bins disappear.
How best can I build and remove items with a single click? Store in a session parameter and then
a. remove the latest click if it matches whats in the session
b. add the latest click if its not already in the session
Then submit whatever the array is at that stage?
Or, is there a better way to run this?
Here's the listeneer
enter code here
document.getElementById("filtering_div").addEventListener("click",function(e) {
// e.target was the clicked element
if (e.target && e.target.matches("input")) {
var parameter = e.target.id;
//console.log("Anchor element", parameter , " was clicked" );
var opts = getCatalogueFilterOptions(parameter);
console.log(opts);
// update_nav_filter(opts);
updateCatalogue(opts);
}
});
You have a "delegation" problem. When you create a dynamic element, in order to be able to act on the newly created element, you have to reference it as a child element that was originally loaded with the DOM.
For example, if you have an element called <div id="top"></div> and you create a dynamic element, let's say <button id="test">Click</button> in there, you'll have to refer to that div when adding an event listener.
$("#top").on('click', '#test', function(){
//event related code goes here.
});
Here is a fiddle I created that explains the whole thing with some examples.
If you have any questions about it, please let me know.

How to grab a hidden input's attributes using Google Tag Manager Click Event

I have hidden inputs being created dynamically and populated using angularjs like so:
<input type="hidden" id="input-{{counter_here}}" name="{{dynamic_name_here}}"
value="dynamic_value_here" />
I want to use Google Tag Manager (GTM) to track some data based on the inputs' attriibutes.
I'm using javascript like so
for(var i = 0; i < my_array.length; i++){
$('#input-' + i).click();
}
... so that I can fire a click event on each of these inputs (as there could be multiple instances of these inputs), thereby triggering a tag in GTM.
I know that in GTM I can use the built in variable "Click ID" to get the id attribute of the input when clicked. But what I need is the name and value attributes to be recorded; the name in GTM's 'action' and the value in GTM's 'label'. GTM's 'value' can be left as default.
Any ideas?
UPDATE
I've tried using
{{Click Element}}.getAttribute('name') // and
{{Click Element}}.getAttribute('value')
... like so:
But when I preview I just get a string returned instead of the values:
The Event Action and Event Label are both processed as strings, as you have found out. The easiest solution inline with the approach you are attempting is to create new JavaScript variables for each of the attributes:
Then update your Event tags with the new JavaScript variables:

Disable AJAX button after nth click

Given I have a model Post which can have up to n Comments (the number is controlled by the Backend) and I have a view which allows to add a Comment via a AJAX request. What is the best way to tell the view upon the nth request to disable the Add-Comment-Form?
The nth request is successfull so status code should still be 200/201 but the backend already "knows" that the nth + 1 call will invalidate the Post, so i want to somehow tell this to the view so it can take action before the user experiences the (catched) error upon nth + 1 submit.
By now the backend renders html which is then simply attached to a div in the DOM, with JSON I might add an additional field but then would move the templating to the view again.
If someone has an idea for an elegant solution?
Try having your server render javascript value for comment count and max comments. Then you can increment the count value in your success function as well as perhaps render the html comment.
Something like
var commentCount = *value from server*;
var maxComments =*value from server*;
$('#mybutton').click(function(){
$.ajax({
// your code here
})
. success(function (response) {
// process response
commentCount ++;
if( commentCount >= maxComments)
$('#mybutton). prop('disabled', true);
});
Just hide the "Add comment" button by JavaScript, when it will be "nth + 1". Or remove eventListener from button and change caption to smth like "You reached max comments".
Keep a track of the number of clicks. After the n th click, you can change the disabled attribute of your button to true.
$(".myButton").attr("disabled",true);

jQuery Mobile and MVC3 auto submit

The following code works perfectly if I take jQuery Mobile out of the question!
The form:
#using (Html.BeginForm("SearchTown", "Home", FormMethod.Post, new { id = "TheForm1" }))
{
#Html.DropDownList("TownID", (SelectList)ViewBag.TownId, "Select a Town")
}
The Javascript:
<script type="text/javascript">
$(function () {
$("#TownID").live('change', function () {
//$("#TownID").change(function () {
var actionUrl = $('#TheForm1').attr('action') + '/' + $('#TownID').val();
$('#TheForm1').attr('action', actionUrl);
$('#TheForm1').submit();
});
});
</script>
But if I wrap jQuery Mobile around the site, then every time I submit the form, in my log only it tacks the ID field again and again to the end of the URL string. This only happens in my log, not in the browser. In the browser it still looks like it’s doing the right thing! E.g..
www.mysite.com/Home/SearchTown/2 the first time
www.mysite.com/Home/SearchTown/2/2 the second time
www.mysite.com/Home/SearchTown/2/2/2 the third time
But in the browser it still looks correct www.mysite.com/Home/SearchTown/2
Why is jQuery Mobile doing this?
This is most likely happening because each time you POST the form, it uses AJAX to load the response and the loaded page has repeated element IDs in it.
I'm guessing here, but based on what you described it sounds like your form posts back to a page with the same form markup on it. Each time your form post renders the next page you'll get another #TheForm1 added to your DOM (as jQuery Mobile keeps previously loaded pages in the DOM and simply swaps between active data-role="page" elements). Due to this behavior, once you have more than one #TheForm1 on the page, the selector $('#TheForm') will only ever return the first element in the DOM matching that ID- which will be the form which you posted the very first time. Thus, each time you you post, your code will use the action attribute of the form element you modified originally- which is why you see multiple values appended to the URL.
In jQuery Mobile it is almost always better to identify elements using a class name and the active page as the container, as you never know how many times an ID might be repeated in the DOM across multiple page changes. So, instead of using $('#TheForm1'), assign a class name and use that in conjunction with $.mobile.activePage: $('.Form1', $.mobile.activePage). (The same goes for your select box).
As an alternative, you can tell jQuery Mobile to not enhance your form by adding data-ajax="false" to the form tag. This will cause it to behave like a normal full page postback without any AJAX.
Edit
The point I am making in paragraph 3 is that you need to make sure you're always selecting the correct form element for the currently visible page, rather than unintentionally returning one which is hidden from view. The $.mobile.activePage global variable will give you the context of the currently visible page, and then a class-based selector (rather than Id-based) will ensure that the correct form element is retrieved in the change handler. Something like this:
<form class="town-form" action="#">
<select class="town-selector">
<option value="1">Town A</option>
<option value="2">Town B</option>
<option value="3">Town C</option>
</select>
</form>
<script type="text/javascript">
$(function () {
$(".town-selector").live('change', function () {
var form = $('.town-form', $.mobile.activePage);
var actionUrl = form.attr('action') + '/' + $(this).val();
form.attr('action', actionUrl);
alert('submitting to: ' + form.attr('action'));
form.submit();
});
});
</script>
because you are submitting the hole page and jQuery mobile does not fancy such thing, and after each POST it just appends the ID into the document.location... I have learned that in some mobile projects...
instead of this line $('#TheForm1').submit(); do something like this:
var url = $('#TheForm1').attr('action') + '/' + $('#TownID').val();
$.post(url, $('#TheForm1').serialize(), function(data) {
// do something with data if you send back something...
// or just change page with jQuery Mobile API
});
return false;
Iv'e left this one up long enough and no one has an answer!

JQTouch: passing data between 'views'

Hi I have been playing around with jqtouch today and I'm just wondering how to manage data.
I tried looking around but couldn't see much documentation.
If I had a list of links for say products? And I click on one i can navigate to the product 'view'. How to I pass variables like you would a $_GET variable to select THAT product?
Or even if I set the id of the link to the id of the record and use JS to grab the ID and somehow pass it to the next view?
Any help with this would be most appreciated!
NOTE: I also want to use it with the offline extension so I'm not sure get ajax would work
Regards,
Billy
You can use the referrer property for the data object. The link would look like:
Product #1
where the HTML ID would correspond to the product ID. Then in the "pageAnimationEnd" event you can retrieve the product details like this:
$('#view').bind('pageAnimationEnd', function (e, info) {
// get the id of the calling href
var id = $(this).data('referrer')[0].id;
$.getJSON('/products/' + id, function (data) {
// do something with the data
});
});
You could look at the demo to see how it does form submission, i.e. AJAX > POST Form Example. Essentially, you create a form and a jQT-style submit button:
<form id="ajax_demo" action="ajax_demo.php" method="POST" class="form">
...
<a class="submit whiteButton" href="#">Submit</a>
</form>
Then in your receiving page (i.e. ajax_demo.php), you can access the form fields, e.g. PHP's $_GET or JavaScript's location.search.
Another way is to store the data in the DOM with jQuery:
// in global level
$('body').data('ajax_demo', "some data for the page");
// in page/view level
$('#ajax_demo').data('key', 'value');

Categories