Reliable way of knowing when BigCommerce checkout form has loaded - javascript

I'm trying to listen for when the form is loaded on the BigCommerce checkout page.
We need to add address validation to the page (+ disable all except first address field so it's auto populated by the address validation service we're using).
The address validation service's JavaScript is firing before the form elements exist because the BigCommerce checkout page works by dynamically adding HTML to the page with JavaScript links which then load the form.
I was thinking of using one of
Polling, setTimeout repeatedly at say 200 millis until some known element exist
Using MutationObserver which seems to do what I want https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver - I can control the div inside which the form is loaded so use mutation ovbserver to listen for "subtree" events but reading the MDN docs it was clear what subtree really means and/or when it fires
Any suggestions?

If you are on Optimized One Page Checkout, you will definitely want to go with the Mutation Listener.
This Blog Post by the BC team includes some really handy Mutation Listener code that I've leveraged on multiple checkout customizations:
https://medium.com/bigcommerce-developer-blog/the-complete-guide-to-checkout-customization-on-bigcommerce-6b566bc36fa9
Word of warning - the OPC checkout is an external application - not included in the base Cornerstone Repo source code at all. I believe it's a React App. If you are familiar with how React and other frameworks handle conditional rendering, they will often un-mount and re-mount components/HTML elements in response to their internal state.
For example, when you move from the "Shipping Details" step to the "Billing Details" step on checkout, the shipping details DOM nodes are completely un-mounted from the page.
This means that anything you've attached to them via JS/JQuery, such as event listeners, will be gone. You'll need to configure the mutation listener to listen for mounting of every single section that you need to do work on, not just the entire checkout app. This makes checkout customizations fairly tricky to handle.
Another issue - if you want to over-write the input field values, you're going to be fighting with the React app, once again. As I've mentioned, React contains an internal state which controls the values of the address inputs. You can try to use JS to change the value of those inputs, but the internal state within the React app corresponding to those fields will not update. You will need to either use the checkout storefrontAPI to update those values,or you will need to use a hacky solution to manually trigger React's internal synthetic event emitter after updating the values with your JS code, I've used this library to some success:
It's not an ideal solution at all.
https://github.com/vitalyq/react-trigger-change
Preferably, if you need tight control over checkout, you can develop a customized checkout solution using the checkout-sdk that BC provides, but this is not a light task, as it's more a set of building blocks for building custom checkout flows rather than something you can drop in and start customizing right away.

Related

How do I locate the function that is stealing DOM focus?

I'm trying to debug the integration between my app and Stripe's Elements component library. Everything works fine in sandbox mode, but we ran into a problem on production in the 3D Secure authentication process. This involves loading an iframe, into our app, that contains a form from the credit card's issuer (usually via a technology partner, like Arcot).
The form loads correctly and its buttons are working as expected, but the element (for a SMS one time code) is not behaving. Every time I click on the input, something is immediately pushing the focus back to the element of the iframe. This makes it impossible to type anything in, since by the time I touch a key, the input is not in focus. For reference, it is possible to change the input's value using document.getElementById('enterPIN').value = '123456';
I'm not sure if my app is triggering focus() calls (I don't think so) or if it is some part of the iframe code or even Stripe's. Is there a good way to monitor DOM events and do a stack trace for the trigger of each one?
I tried two tactics. Neither gave an obvious answer, but they did point my search in the right direction.
I opened the Event Listeners panel (in the Elements tab of my browser's developer tools) and removed everything I could find, but it seems that this doesn't actually change the behavior of the page- focus kept being stolen away. Luckily, I also noticed some listeners that were defined by the Material UI library.
I used monitorEvents() to get a few more details, but the src & target values were not much help and event.relatedTarget was always null.
In the end, I found this discussion and realized that my MUI Dialog component was stealing focus whenever I clicked on the iframe triggered by its content. This was easily fixed by adding the disableEnforceFocus attribute.

How do you design and implement an application wide event detection mechanism to capture click events in a large scale Angular application?

I'm trying to implement a solution to report detailed user activities to Google Analytics. Since the application is a single page application I know that I can capture the page change events from router, but this is only the basic part of the solution which is only for reporting seen pages.
Main point is since this is a large scale application containing 500+ pages/components and I don't want to create a logger service requires to change every page by adding it, I need to figure out a way to determine a centralized or application wide place to catch and detect button click events and maybe the pages they are fired from. Then I hope to be able to report detailed user activities on related pages to analytics like X button clicked from Y page.
For a central place I know there are interceptors for HTTP events, and router for page changes. Besides that I know maybe I can use change detection with hooks, but I'm not sure about should I have to work with hooking into application lifecycle level.
How can I implement a mechanism to catch and detect component elements events with related pages in Angular? Are there any best practices or abstractions that framework provides that may I utilize?
Note: I've learned that Google Tag Manager does the job specifically for the analytics purposes, but my question remain same which how to implement it with Angular.
Custom event API is one option, but you have to despatch that event in all clicks.
So using HostListner we can achieve this.
Add a listener in the main component ie in app.componnet
#HostListener('window:click', ['$event'])
onClickEvent(event: MouseEvent) {
var target = event.target || event.srcElement;
var id = target['id']; //this will be the id of the target that you clicked
this.clickedValue = id;
}
And follow a naming pattern while you adding the id of each item. ie add the component name as the prefix of id. After prod build, the component name will be minified to one-letter name, it loses its original name.
For eg: if you have component mychild.component
<div>
<h1 id="mychild-h1">Test</h1>
</div>
Here, id is myChild-h1 and you can pick the components name from it. Now you have the id and name of the component that you clicked and create a service to log that info.
Attaching one sample code for check
CheckThis

Disabling turobolinks to serve page specific javascript

I you have a highly interactive event driven page in rails 5.0.0.1 with Turbolinks.
Having different interactions on different pages, events like window.resize will trigger on pages where I don't really need it.
Is it worth to sacrifice navigation time by disabling Turbolinks to serve page specific javascript, or should I not care and just use if statement in Jquery to check if certain elements are present in the page using their ID.
What is the rails way of doing this?
It is not recommended to serve page specific assets such as javascript. This slows down the user experience since navigating to a new page triggers another asset download.
The whole point of the Rails Asset Pipeline is to gather your assets, minify them and concatenate them all into a single file that the browser downloads only once, the first time a user navigates to your page.
Yes, use jQuery to check if certain elements exist to run some behavior.
The way I've found useful is to not think about js behaviors as page specific but rather, widget specific. e.g. if there's a sortable table in the DOM then initialize the sortable table widget i.e. $(".sortable").sortable()
The above example uses the jQuery plugins pattern. Place your behavior/widget logic inside the jQuery plugin and it will only run when the selector finds elements e.g. $("#nonexistant").something(), something() will not be called. $("#definitelyExists").somethingElse(), somethingElse() will be called.
In the preceding examples, when an element is found and the function is called, the this of the function references the matched elements and you can run your behavior logic on them.

How to perform navigation in Windows Store App using Blank App Template

I'm making a game using JavaScript, currently I'm using window.location = "somepage.html" to perform navigation but I'm not sure if that is the correct way to do it. As I said in the title I've choosed Blank App Template so I do not have any navigator.js or something like.
Can you guys tell me the best way to do it?
Although you can use window.location to perform navigation, I'm sure you've already noticed a few of the downsides:
The transition between pages goes through a black screen, which is an artifact of how the underlying HTML rendering engine works.
You lose your script context between pages, e.g. you don't have any shared variables or namespaces, unless you use HTML5 session storage (or WinRT app data).
It's hard to wire up back buttons, e.g. you have to make sure each destination page knows what page navigated to it, and then maintain a back stack in session storage.
It's for these reasons that WinJS + navigator.js created a way to do "pages" via DOM replacement, which is the same strategy used by "single page web apps." That is, you have a div in default.html within which you load an unload DOM fragments to give the appearance of page navigation, while you don't actually ever leave the original script context of default.html. As a result, all of your in-memory variables persist across all page navigations.
The mechanics work like this: WinJS.Navigation provides an API to manage navigation and a backstack. By itself, however, all it really does is manage a backstack array and fire navigation-related events. To do the DOM replacement, something has to be listening to those events.
Those listeners are what navigator.js implements, so that's a piece of code that you can pull into any project for this purpose. Navigator.js also implements a custom control called the PageControlNavigator (usually Application.PageControlNavigator) is what implements the listeners.
That leave the mechanics of how you define your "pages." This is what the WinJS.UI.Pages API is for, and navigator.js assumes that you've defined your pages in this way. (Technically speaking, you can define your own page mechanisms for this, perhaps using the low-level WinJS.UI.Fragments API or even implementing your own from scratch. But WinJS.UI.Pages came about because everyone who approached this problem basically came up with the same solution, so the WinJS team provided one implementation that everyone can use.)
Put together then:
You define each page as an instance of WinJS.UI.Pages.PageControl, where each page is identified by its HTML file (which can load its own JS and CSS files). The JS file contains implementations of a page's methods like ready, in which you can do initialization work. You can then build out any other object structure you want.
In default.html, define a single div for the "host container" for the page rendering. This is an instance of the PageControlNavigator class that's defined in navigator.js. In its data-win-options you specify "{home: }" for the initial page that's loaded.
Whenever you want to switch to another page, call WinJS.Navigation.navigate with the identifier for the target page (namely the path to its .html file). In response, it will fire some navigating events.
In response, the PageControlNavigator's handlers for those events will load the target page's HTML into the DOM, within its div in default.html. It will then unload the previous page's DOM. When all of this gets rendered, you see a page transition--and a smooth one because we can animate the content in and out rather than go through a black screen.
In this process, the previous page control's unload method is called, and the init/load/processed/ready methods of the new page control are called.
It's not too hard to convert a blank app template into a nav template project--move your default.html/.css/.js content into a page control structure, add navigator.js to default.html (and your project), and put a PageControlNavigator into default.html. I suggest that you create a project from the nav app template for reference. Given the explanation above, you should be able to understand the structure.
For more details, refer to Chapter 3 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, where I talk about app anatomy and page navigation with plenty of code examples.

Can I track changes to a web form using webtrends?

Does anyone know of a way to track changes to a web form, i.e. select or text field using webtrends?
I know Google Analytics has similar functionality, can this be done in WebTrends?
Webtrends has Javascript click tracking so you'd have to add Javascript onChange or onClick events to whatever you need to track.
Since web forms don't typically trigger the Webtrends link tracking, you have to use the dcsMultiTrack function, passing the variables that need to be tracked.
For example, you might use the following to track the URL that you're on and the fact that a particular field was clicked:
onClick="onclick="dcsMultiTrack('DCS.dcssip','www.domain.com','DCS.dcsuri','/yourpage', 'WT.ti','formfield1','WT.dl','1');"
Note that the WT.dl parameter should be set so you don't count extra page views. Also note that the WT.ti parameter is used for automatically tracking this as a link click. If you need more granularity, you can always define another variable (for example, "formname) and configure Webtrends to report on that as another dimension.

Categories

Resources