How to remove datalayer from history event with react-gtm-module - react-gtm-module

When I add a custom datalayer as described here it will fire a message that can be seen in the G-Tagmanager with the added datalayer, but it will also show in every rout-/ history change event after that.
Here is what I have so far:
const tryToSendGADataLayer = () => {
const tagManagerArgs = {
dataLayer: {
ecommerce: {
purchase: {
actionField: {..},
products: [{..}]
}
}
},
dataLayerName: 'ecommerce'
}
TagManager.dataLayer(tagManagerArgs)
}
I only want the datalayer to be added in the Message event and not in all the events after that.

window.google_tag_manager[ GOOGLE_TAG_MANAGER_ID].dataLayer.reset()
GTM does not reset dataLayer on page navigation

Related

View not showing up when an extension command is typed/selected

I'm creating a vscode client extension that needs to show
Shows a webview on the Primary Sidebar (already works)
Opens a view when a certain extension command is selected (it fails)
The package.json looks like this
"activationEvents": [
"onView:navCode.search",
"onLanguage:typescript",
"onCommand:navCode.start"
],
"main": "./dist/extension",
"contributes": {
"commands": [
{
"command": "navCode.start",
"title": "Show class diagram",
"category": "NavCode Diagram"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "nav-code-search",
"title": "Nav Code",
"icon": "images/nav-code-logo.png"
}
]
},
"views": {
"nav-code-search": [
{
"type": "webview",
"id": "navCode.search",
"name": "Code search"
}
]
}
},
The activate method of my extension looks like these
export function activate(context: vscode.ExtensionContext) {
let refManager = new ReferenceManager();
refManager.updateWorkspaceReferences();
//Register the webview for code nav search
const provider = new SearchViewProvider(context.extensionUri, context, refManager);
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(SearchViewProvider.viewType, provider)
);
context.subscriptions.push(// Create and show a new webview
vscode.commands.registerCommand('navCode.start', () => {
const panel = vscode.window.createWebviewPanel(
'navCode', // Identifies the type of the webview. Used internally
'NavCode - Class Diagram', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{} // Webview options. More on these later.
);
})
);
}
The command appears correctly
But when is selected it shows this error
There is nothing else on Console or Output views, what could be causing this ?
I have searched without any success about how to register multiple views of the same extension
UPDATE
But back to the problem I believe that is realted to this method
refManager.updateWorkspaceReferences();
Because it awaits until a typescript parses all the *.ts files of the current workspace
public async updateWorkspaceReferences() {
let message: string;
let folders = vscode.workspace.workspaceFolders;
if (folders && folders.length > 0) {
message = await this.processProject(folders[0]);
}
else {
message = 'nav-code requires an open workspace to work';
}
this.log.append(message);
}
How can a have a running task, right after the extension is activated ? can I use threads ?
Here is an overview of what I ended up doing to solve the problem
Put the long-running logic inside the SearchViewProvider (not running directly inside the activate method but as a promise that notifies when done
SearchViewProvider gets notified by ReferenceManager that the long-running logic has finished using BehaviorSubject (rxjs) : referencesUpdated
The view is initialized with a default content when notified the content is refreshed.
Here is the relevant code
extension.ts
export function activate(context: vscode.ExtensionContext) {
//Register the webview for code nav search
const provider = new SearchViewProvider(context, logger);
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(SearchViewProvider.viewType, provider)
);
context.subscriptions.push(// Create and show a new webview
vscode.commands.registerCommand('navCode.start', () => {
const panel = vscode.window.createWebviewPanel(
'navCode', // Identifies the type of the webview. Used internally
'NavCode - Class Diagram', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{} // Webview options. More on these later.
);
})
);
}
SearchViewProvider.ts
constructor(
private context: vscode.ExtensionContext,
private logger: Logger
) {
this.extensionUri = this.context.extensionUri;
this.referenceManager = new ReferenceManager(logger);
this.referenceManager.referencesUpdated.subscribe(() => { this.refreshView() });
}
public resolveWebviewView(webview: vscode.WebviewView, context: vscode.WebviewViewResolveContext<unknown>, token: vscode.CancellationToken): void | Thenable<void> {
this.view = webview;
if (this.view) {
/** existing view logic **/
this.refreshView();
}
}
refreshView() {
if (this.view) {
this.view.webview.html = this.buildView(this.view.webview);
}
}

Event for view leave

I declared a controller for a view in my SAPUI5 application. Now I want to perform tasks when the view is left by the user.
There is already a possibility to add a callback function to attachRoutePatternMatched to perform tasks when the view is navigated by the user now I need a equivalent function to handle a leave of the view. I use a SplitContainer as parent container
onInit: function() {
this._oRouter = this.getOwnerComponent().getRouter();
this._oRouter.attachRoutePatternMatched(this._routePatternMatched, this);
},
_routePatternMatched: function(oEvent) {
var that = this;
var sRouteTargetName = oEvent.getParameter("name");
if (sRouteTargetName === "myView") {
// perform tasks if the view is opened by the user
}
},
You can try if this works:
navAway: function(viewName, callback) {
this._oRouter.navTo(viewName);
if(callback && typeof(callback) === "function") {
callback();
}
}
e.g. this.navAway("myView", function() { //doStuff });
Presume you mean navigating backwards? If you have a back button, which presumably you must, put your actions in that function. E.g your detail/master has a navBack button in the toolbar, so put your logic in the button's event handler...
You can achieve this with BeforeHide delegate on the NavContainer child which is often the view:
onInit: function() {
this._navDelegate = { onBeforeHide: this.onBeforeLeave };
this.getView()/*<-- navContainerChild*/.addEventDelegate(this._navDelegate, this);
},
onBeforeLeaving: function(event) {
// ... do something
},
onExit: function() {
// detach events, delegates, and references to avoid memory leak
this.getView().removeEventDelegate(this._navDelegate);
this._navDelegate = null;
},
Example: https://embed.plnkr.co/wp6yes?show=controller%2FNext.controller.js,preview%23next
API reference: NavContainerChild
API reference: sap.ui.core.Element#addEventDelegate
For other navigation related events, see documentation topics mentioned in https://stackoverflow.com/a/55649563

How do I submit a form using a store under ExtJs?

Is there a way to have a form submit create an object in a store under ExtJs 4?
It seems strange to me that the grid is built completely around the store mechanism and I see no obvious way to plug a form into a store. But I am most likely just missing something.
You can add a model instance to a store upon form submit using this code:
onSaveClick: function()
{
var iForm = this.getFormPanel().getForm(),
iValues = iForm.getValues(),
iStore = this.getTasksStore();
iStore.add( iValues );
},
This is within an MVC controller, so this is the controller.
For model editing, you can 'bind' a form to a model instance using loadRecord:
iFormPanel.loadRecord( this.selection );
You can then update the model instance using updateRecord():
iFormPanel.getForm().updateRecord();
Just for fun (and as it might help some), it is similar to the following code:
onSaveClick: function()
{
var iForm = this.getFormPanel().getForm(),
iRecord = iForm.getRecord(),
iValues = iForm.getValues();
iRecord.set ( iValues );
},
If your store is has autoSync: true. An Update (or Create) call will be made via the configured proxy. If there's no autoSync, you'll have to sync your store manually.
You can subclass Ext.form.action.Action to provide load/save actions for a Form to be performed on a Store. The only gotcha is that somehow there's no "official" way to select any non-standard Action in Ext.form.Basic, so I'd suggest an unofficial override:
Ext.define('Ext.form.Advanced', {
override: 'Ext.form.Basic',
submit: function(options) {
var me = this,
action;
options = options || {};
action = options.submitAction || me.submitAction;
if ( action ) {
return me.doAction(action, options);
}
else {
return me.callParent(arguments);
}
},
load: function(options) {
var me = this,
action;
options = options || {};
action = options.loadAction || me.loadAction;
if ( action ) {
return me.doAction(action, options);
}
else {
return me.callParent(arguments);
}
}
});
And, having created the Actions you need, you could then use them in a Form Panel:
Ext.define('My.form.Panel', {
extend: 'Ext.form.Panel',
requires: [ 'Ext.form.Advanced' ],
loadAction: 'My.load.Action',
submitAction: 'My.submit.Action',
...
});
There are other ways and shortcuts though.

How do I know that I'm still on the correct page when an async callback returns?

I'm building a Metro app using the single-page navigation model. On one of my pages I start an async ajax request that fetches some information. When the request returns I want to insert the received information into the displayed page.
For example:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
WinJS.xhr(...).done(function (result) {
element.querySelector('#target').innerText = result.responseText;
});
}
};
But how do I know that the user hasn't navigated away from the page in the meantime? It doesn't make sense to try to insert the text on a different page, so how can I make sure that the page that was loading when the request started is still active?
You can compare the pages URI with the current WinJS.Navigation.location to check if you are still on the page. You can use Windows.Foundation.Uri to pull the path from the pages URI to do this.
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var page = this;
WinJS.xhr(...).done(function (result) {
if (new Windows.Foundation.Uri(page.uri).path !== WinJS.Navigation.location)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};
I couldn't find an official way to do this, so I implemented a workaround.
WinJS.Navigation provides events that are fired on navigation. I used the navigating event to build a simple class that keeps track of page views:
var PageViewManager = WinJS.Class.define(
function () {
this.current = 0;
WinJS.Navigation.addEventListener('navigating',
this._handleNavigating.bind(this));
}, {
_handleNavigating: function (eventInfo) {
this.current++;
}
});
Application.pageViews = new PageViewManager();
The class increments a counter each time the user starts a new navigation.
With that counter, the Ajax request can check if any navigation occurred and react accordingly:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var pageview = Application.pageViews.current;
WinJS.xhr(...).done(function (result) {
if (Application.pageViews.current != pageview)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};

GWT/MVP: detecting change events in a table with proper MVP pattern

We're using gwt-presenter, but not really a question specific to that...
I've got a table with users in it. As I build the table in the view (from the data provided by the presenter), I need to add two action buttons ("Edit", and "Delete") at the end of the row.
What's the best way to assign click handlers to these buttons so the presenter knows which was clicked? Previous to this, we could pass a private field from the view to the presenter and attach a discrete click handler to that button. However, this method is rather rigid and doesn't work in this scenario very well.
Thanks in advance.
How about having the view allowing the subscription for edit/delete click events, registering internally the individual row click events, and then delegating the event handling to the ones registered by the view?
I mean something like the following pesudo code:
View:
addRowEditClickHandler(ClickHandler handler) {
this.rowEditClickHandler = handler;
}
addRowDeleteClickHandler(ClickHandler handler) {
this.rowDeleteClickHandler = handler;
}
//... somewhere when setting up of the grid...
rowEditButton.addClickHandler = new ClickHandler() {
onClick(args) {
this.rowEditClickHandler.onClick(args)
}
rowDeleteButton.addClickHandler = new ClickHandler() {
onClick(args) {
this.rowDeleteClickHandler.onClick(args)
}
Presenter:
View view = new View();
view.addRowEditClickHandler( new ClickHandler() {
onClick(args) {
doSomething();
}
});
view.addRowDeleteClickHandler( new ClickHandler() {
onClick(args) {
doSomething();
}
});