GTM Event on Content - javascript

I can't see to find an answer to this one anywhere. I'm trying to setup a trigger and event tag in Google Tag Manager to fire whenever content is present. Essentially, I am creating a simple event in Google Analytics for Product Views. The developer for this site is expensive, so I'd like to handle it purely in GTM.
One piece of content that only exists on product pages is the submit on the cart button.
Can anyone recommend a method to inject some code with GTM to fire when content exists so I can trigger a tag off it?
Here is the html in and around the cart button. I'm thinking that I can fire something when class="clsAddCartRight" exists or the submit - either one:
<div id="variationGroup" class="clsViewItemVariationGroup clsOverflow" style="clear:both;">
<div class="clsViewItemVariationList clsOverflow" style="width:200px;margin:0 auto;">
<select name="item_variations" id="item_variations_496" onchange="getDetails()">
<option value="1606" selected="selected">Medium</option>
<option value="1607">Large</option>
</select>
</div>
<div class="clsItemSaleDetailBlockBottom">
<form name="purchaseItemFrm" id="purchaseItemFrm" action="http://www.runwaycrush.com/marketplace/cart.html" method="post">
<input type="hidden" name="item_id" id="item_id" value="1602">
<input type="hidden" name="c_action" id="c_action" value="add">
<input type="hidden" name="item_ref" id="item_ref" value="kanduclothing">
<input type="hidden" name="item_matrix_id" id="item_matrix_id" value="4721">
<div class="clsItemCartBlock clsFloatRight" id="addCartButton" style="margin:20px auto 0px; width:318px;">
<div class="clsAddCartLeft">
<div class="clsAddCartRight">
<input type="submit" name="add_to_cart" id="add_to_cart" value="ADD TO CART">
</div>
</div>
</div>
</form>
</div>
</div>

You can use a DOM type variable in GTM and use the "CSS Selector" option to select the element by classname (if the same class is there multiple times it will pick the first occurence). If you set the attribute name field to "class" the value for that variable will be the value of the class attribute.
Actually I think it would be better if you use the button itself and look for the "id" attribute with the value of "add_to_cart", because ids are unique per page (or should be).
However you also need an event to trigger a tag.
The value will be available only after the DOM has rendered. So the easiest way would be to set up a pageview and set the trigger type to "DOM Ready" and have if only fire when the value of your DOM variable matches the classname (or id respectively) of the button.
However if your product page urls follow any recognizable pattern it would be a lot better to use a url filter in a pageview trigger. That way you could have your tags trigger on pageload, which for many tags is much preferable.

Related

Send combination of two input values with htmx

I'm writing a simple website with Django and I decided to try htmx library in client side to load html fragments. Now I want to sort lists by different fields, ascending and descending. I have something like this:
<div class="col-auto">
<div class="input-group input-group-sm">
<select id="np-sort-key" name="key" class="form-select">
<option value="publish_date" selected>Publish date</option>
<option value="title">Title</option>
</select>
<button class="btn btn-outline-dark" type="button">
<span class="bi bi-sort-down"></span> <!-- bi-sort-up for Asc icon -->
</button>
</div>
</div>
I want to add/replace the order_by=<order><key> query parameter to/in the current url (For example /articles?page=2&order_by=-publish_date.) and send it back to Django view both on "select" change and "button" click. The endpoint returns a Html I want to swap it with another Html node with Htmx. (Note that span class should be changed on button click to show sorting is Asc or Dsc)
Is it possible using htmx? If not, simple Javascript solutions are welcome.
You could solve it like this:
You use
<form hx-get="...">
...
<input type="hidden" name="order_by">
</form>
Then you can display the user a nice icon for sorting. If the user clicks on the icon, you update the hidden input via JS.
The easiest approach would be to construct the URL server side based on the input values and then push it using the HX-Push response header:
https://htmx.org/reference/#response_headers
From what I understood of htmx documentations, htmx provides us two tools to send custom values:
hx-vals that lets you add custom parameters to the ongoing request. These parameters are in the form of a Json object and their values could be either static or dynamic (returned from a JS function). For example:
<div hx-get="/list" hx-vals='js:{"order_by": concatSortOrderAndKey()}'>
hx-include that adds values of the elements specified by a query selector to the ongoing request.
In case of my problem, in addition to #guettli answer, I could set htmx parameters on "select" and "button" tag and use hx-vals to calculate new order_by value. (also by using hx-boost, hx-* stuff could be set only on outer enclosing elements). But overall, I think the hidden input was a better solution.

Vue.js - How to bind to form elements generated after page load?

I have form elements aren't available in the html document until an inline script runs on page load. How to I bind to these form elements in Vue.js after the page loads? Obviously with jQuery I could do a $('.element').each(), but what is the 'Vue way'? I need to set the valueattribute of the hidden inputs.
<form>
<input type="hidden" name="AST_Goals__c" class="mktoField mktoFieldDescriptor mktoFormCol" value="" style="margin-bottom: 10px;">
<input type="hidden" name="Perception_of_AppSec_program__c" class="mktoField mktoFieldDescriptor mktoFormCol" value="" style="margin-bottom: 10px;">
</form>
You might not need to access the DOM in this case...
Based on the Marketo docs that show an example of setting a hidden field's value, you could use form.vals() in the MktoForms2.loadForm()'s callback:
MktoForms2.loadForm('//app-ab00.marketo.com', '785-UHP-775', 1057, form => {
form.vals({
AST_Goals__c: 'my goal',
Perception_of_AppSec_program__c: 'my perception'
})
})
The answer for me was to call the MktoForms2.loadForm() function in the js file, not within <script> tags in the html file. You can't bind vue elements within inline <script> tags.

First form of nested form tags not responding to css display:none

I have nested form tags like this
<form>
<h5>Main Form</h5>
<input type="text" />
<!-- Don't Show This Form -->
<form style="display:none">
<input type="text" />
<input type="text" />
</form>
<!-- Don't Show This Form -->
<form style="display:none">
<input type="text" />
<input type="text" />
</form>
</form>
The problem is the first form displaying although It's display none css inline
See the code in action http://jsfiddle.net/fZMKB/
I know I know, nested forms is against the rules But I have to use it this way for this reason
I need to reset bunch of inputs and form elements before jQuery event and I'm using this code
$('form').get(0).reset();
From this my earlier question How to reset forms elements (input,select,textarea,etc.) on events using jQuery
So the only reason I use form tag is I need to reset inputs and textarea, etc..
There's never a good reason to have nested forms. Instead, use proper HTML syntax and adjust your jQuery code accordingly. Here's some valid HTML markup:
HTML
<form>
<h5>Main Form</h5>
<input type="text">
<div class="one" style="display:none">
<input type="text">
<input type="text">
</div>
<div class="two" style="display:none">
<input type="text">
<input type="text">
</div>
</form>
Let's say you want to reset all text inputs, checkboxes, radio buttons, and select menus in the first subsection. This would only take two simple lines of jQuery:
$(".one input, .one select").val("");
$(".one textarea").html("");
If you want to restore default values, you should store the values in the HTML markup using the data attribute. Here's an example: http://jsfiddle.net/pgNrF/3/
You cannot have nested forms in HTML , you can have different forms but not nested
See this http://www.w3.org/TR/2011/WD-html5-20110525/forms.html#the-form-element
Content model
Flow content, but with no form element descendants.
No, nested forms are forbidden.
This is expressed in the HTML 4.01 DTDs as:
<!ELEMENT FORM - - (%block;|SCRIPT)+ -(FORM) -- interactive form -->
— http://www.w3.org/TR/html4/interact/forms.html#h-17.3
A FORM has a mandatory start tag, mandatory end tag and can contain anything in %block or SCRIPT, except other FORMs.
XML DTDs aren't as expressive as SGML DTDs so in XHTML this rule is specified only in the human readable text of the specification:
form must not contain other form elements.
— http://www.w3.org/TR/xhtml1/#prohibitions
HTML 5 isn't an SGML application and doesn't have an official machine readable description of the language. It also expresses this rule in text:
Content model:
Flow content, but with no form element descendants.
— http://www.w3.org/TR/html5/forms.html#the-form-element
Reference

Delegate JS events to different objects

I'm trying to re-skin the input type file element.
I do this by placing two elements on top of each other. One of them is the input tag and the other is a nice button. Something like this:
<input type="file" id="filesButton" multiple>
<input type="button" id="filesButtonOverlay" value="Add Files">
The button has some nice effects when a user hovers, clicks, etc (all done is CSS). However since the input-type-file has a higher z-index (needs to be the case since you can't emulate a click on it) all these effects don't show.
Is there a nice way to delegate all events that input-type-file gets and trigger them on the button?
What if you wrapped the inputs in a div and attached the events to the div? Then target your button with your changes?
I would think you should be able to do this with a shared parent. Then you place the hover on the parent rather than the button itself.
<span id="wrapper">
<input type="file" id="filesButton" multiple>
<input type="button" id="filesButtonOverlay" value="Add Files">
</span>
$("#wrapper").hover(function(){
$("#filesButtonOverlay").dosomething();
});
or in CSS:
#wrapper:hover #filesButtonOverlay{
stuff:
}
If you could potentially have multiple on the same page, you'd want to change to using classes instead of ids

I'm having trouble traversing a newly appended DOM element with jQuery

I have a form that I want to be used to add entries. Once an entry is added, the original form should be reset to prepare it for the next entry, and the saved form should be duplicated prior to resetting and appended onto a div for 'storedEntries.' This much is working (for the most part), but Im having trouble accessing the newly created form... I need to change the value attribute of the submit button from 'add' to 'edit' so properly communicate what clicking that button should do. heres my form:
<div class="newTruck">
<form id="addNewTruck" class='updateschedule' action="javascript:sub(sTime.value, eTime.value, lat.value, lng.value, street.value);">
<b style="color:green;">Opening at: </b>
<input id="sTime" name="sTime" title="Opening time" value="Click to set opening time" class="datetimepicker"/>
<b style="color:red;">Closing at: </b>
<input id="eTime" name= "eTime" title="Closing time" value="Click to set closing time" class="datetimepicker"/>
<label for='street'>Address</label>
<input type='text' name='street' id='street' class='text' autocomplete='off'/>
<input id='submit' class='submit' style="cursor: pointer; cursor: hand;" type="submit" value='Add new stop'/>
<div id='suggests' class='auto_complete' style='display:none'></div>
<input type='hidden' name='lat' id='lat'/>
<input type='hidden' name='lng' id='lng'/>
</form>
</div>
ive tried using a hundred different selectors with jquery to no avail... heres my script as it stands:
function cloneAndClear(){
var id = name+now;
$j("#addNewTruck").clone(true).attr("id",id).appendTo(".scheduledTrucks");
$j('#'+id).filter('#submit').attr('value', 'Edit');
$j("#addNewTruck")[0].reset();
createPickers();
}
the element is properly cloned and inserted into the div, but i cant find a way to access this element... the third line in the script never works.
Another problem i am having is that the 'values' in the cloned form revert back to the value in the source of the html rather than what the user inputs.
advice on how to solve either of these issues is greatly appreciated!
I think you want to use find not filter
$j('#'+id).find('#submit')
That should work in practice, though you've got problems there because there are multiple elements with the same id. I'd change your HTML to use classes, or in this specific case, you don't need either:
$j('#' + id).find(":submit")
have you tried using .val()? and instead of .filter(), use .find()
$j('#'+id).find(':submit').val('Edit');
nickf solution works. (just wrote a piece of code to check that). Do check the definition of filter in jquery documentation.
Reduce the set of matched elements to those that match the selector or pass the function's test.
You have use find in this case. Also as nick mentioned having multiple elements with same id is troublesome, especially when you are doing dom manipulation. Better go with appropriate classes.

Categories