How can i call that function inside that anonymous javascript? (TinyMce example) - javascript

How can i call test() inside that method? It's possible?
(function() {
tinymce.create('tinymce.plugins.WrImagerPlugin', {
init : function(editor, url) {
editor.addCommand('mceWrImagerLink', function() {
//--> how can i refer to test() here?
});
},
test: function () {alert('test');}
}
});
tinymce.PluginManager.add('wr_imager', tinymce.plugins.WrImagerPlugin);
})();

You can make test a regular function and assign it to the object, like this:
(function() {
function test() { alert('test'); }
tinymce.create('tinymce.plugins.WrImagerPlugin', {
init : function(editor, url) {
editor.addCommand('mceWrImagerLink', function() {
test();
});
},
test: test
});
tinymce.PluginManager.add('wr_imager', tinymce.plugins.WrImagerPlugin);
})();
Alternatively, you can keep a reference to the object:
(function() {
var wrImaergPlugin = {
init : function(editor, url) {
editor.addCommand('mceWrImagerLink', function() {
wrImagerPlugin.test();
});
},
test: function() { alert('test'); }
}
tinymce.create('tinymce.plugins.WrImagerPlugin', wrImagerPlugin);
tinymce.PluginManager.add('wr_imager', tinymce.plugins.WrImagerPlugin);
})();
Finally, in this specific case, you should be able to simply call tinymce.plugins.WrImagerPlugin.test().

You can also keep a reference to this in the init method that will be available in the addCommand closure:
(function() {
tinymce.create('tinymce.plugins.WrImagerPlugin', {
init : function(editor, url) {
var me = this;
editor.addCommand('mceWrImagerLink', function() {
//--> how can i refer to test() here?
me.test();
});
},
test: function () {alert('test');}
}
});
tinymce.PluginManager.add('wr_imager', tinymce.plugins.WrImagerPlugin);
})();

Related

Calling function inside another function globally Vanilla JS

Good evening community, I would like you to help me with this logic problem about the functions in vanilla JS.
There is a global function, inside this i made several functions, I would like to know how to access each one independently of the input order.
I have created an example, am I following the right way?
var FEGlobal = {
FEHomepage: {
Init: function () {
this.Cursor();
},
Cursor: function () {
mouseOver();
mouseOut();
},
},
FEMedia: {
Init: function () {
this.MouseOver();
this.MouseOut();
},
MouseOver: function () {},
MouseOut: function () {},
},
BEGlobal: { Init: function () {} },
};
My idea is to make a custom mouseOver / mouseOut functions, what i need to use before they are defined. So in the Cursor function () i wish to call them inside that funcion.
Cursor: function () {
const projectOriginal = document.querySelectorAll("#project__original");
projectOriginal.forEach((element) => {
element.addEventListener("mouseover", function mouseOver() {}, false);
element.addEventListener("mouseout", function mouseOut() {}, false);
});
}

JS works with .include but fails with .extend

I made this JS to add a functionality on a form (backend) that computes a field when the event click is triggered. So far the code recomputes when I use ".include" but the whole JS in all views fail since I'm using ".include". When I try to use extend my code does nothing. Looks like Odoo doesn't add the extended code to the JS engine so my question is, what am I doing wrong here? Is there something else I need to add so my code works as extended?
odoo.define('med_care.TestRenderer', function (require) {
"use strict";
var viewRegistry = require('web.view_registry');
var FormRenderer = require('web.FormRenderer');
var FormView = require('web.FormView');
var TestFormRenderer = FormRenderer.extend({
events: _.extend({}, FormRenderer.prototype.events, {
'click .sign_selector': '_onSignSelectorClicked',
}),
init: function (parent, state, params) {
this._super.apply(this, arguments);
this.fields = state.fields;
this._onSignSelectorClicked = _.debounce(this._onSignSelectorClicked, 300, true);
},
confirmChange: function (state, id, fields, e) {
var self = this;
if (state.model == 'med.test') {
return this._super.apply(this, arguments).then(function () {
self.canBeSaved(self.state.id);
});
}
},
_onSignSelectorClicked: function (event) {
this.state.data.telephone = '333';
if (this.state.model == 'med.test') {
var info_test = {
dataPointID: this.state.id,
changes: {telephone: '333'},
viewType: "form",
notifyChange: true
};
var odoo_event = this.trigger_up('field_changed', info_test);
this.confirmChange(this.state, this.state.id, "telephone",
odoo_event)
}
},
});
var TestFormView = FormView.extend({
config: _.extend({}, FormView.prototype.config, {
Renderer: TestFormRenderer,
}),
});
viewRegistry.add('test_form', TestFormView);
return TestFormView;
});

How to use segment.io's analytics.js in a knockout custom bindings

I am using knockout to make a custom binding for analytics.track, but it seems to be having trouble. It seems if the analytics.track is nested in more than 2 functions the track call fails silently. It doesn't hit the callback and it doesn't report in segments debugger. I have provided 2 examples demonstrating the problem here:
Without Closure (works):
function sendTrack(event, props) {
console.log("Enter sendTrack");
analytics.track('Signed Up', {
plan: 'Enterprise'
}, {}, function () {
console.log('track callback logged');
});
}
ko.bindingHandlers.segmentTrack = {
init: function (element, valueAccessor) {
console.log("Init");
var value = ko.unwrap(valueAccessor());
ko.applyBindingsToNode(element, { click: sendTrack });
}
};
ko.applyBindings({});
With Closure (doesn't work):
(function(ko, $, analytics){
'use strict';
function sendTrack(event, props) {
console.log("Enter sendTrack");
analytics.track('Signed Up', {
plan: 'Enterprise'
}, {}, function () {
console.log('track callback logged');
});
}
ko.bindingHandlers.segmentTrack = {
init: function (element, valueAccessor) {
console.log("Init");
var value = ko.unwrap(valueAccessor());
ko.applyBindingsToNode(element, { click: sendTrack });
}
};
ko.applyBindings({});
})(window.ko, window.jQuery, window.analytics);
Edit1: Also note this works with if I move the analytics.track to init:
(function(ko, $, analytics){
'use strict';
ko.bindingHandlers.segmentTrack = {
init: function (element, valueAccessor) {
console.log("Init");
analytics.track('Signed Up', {
plan: 'Enterprise'
}, {}, function () {
console.log('track callback logged');
});
}
};
ko.applyBindings({});
})(window.ko, window.jQuery, window.analytics);
Please advise
This is very likely because of the order things load / are initialized on the window object. Because the iife executes immediately, the analytics variable will be set to whatever window.analytics is the moment the iife is encountered by the browser. In the first case, window.analytics will be resolved when the code is run.
Put differently: the closure captures window.analytics in a scoped analytics variable at the time the iife executes.
Here's a demo showing the problem.
Without closure:
function sendTrack() {
console.log("Tracking...");
analytics.track("stuff");
}
ko.bindingHandlers.segmentTrack = {
init: function(element) {
console.log("Init");
ko.applyBindingsToNode(element, { click: sendTrack });
}
}
ko.applyBindings({ });
// Simulate loading analytics now:
window.analytics = { track: function(txt) { console.log("Tracking " + txt); } };
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div data-bind="segmentTrack: true">CLICK ME</div>
vs with closure:
(function(ko, analytics) {
function sendTrack() {
console.log("Tracking...");
analytics.track("stuff");
}
ko.bindingHandlers.segmentTrack = {
init: function(element) {
console.log("Init");
ko.applyBindingsToNode(element, { click: sendTrack });
}
}
ko.applyBindings({});
})(window.ko, window.analytics); // window.analytics isn't quite okay yet!
// Simulate loading analytics now:
window.analytics = { track: function(txt) { console.log("Tracking " + txt); } };
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div data-bind="segmentTrack: true">CLICK ME</div>
True, in my examples the second scenario throws an error whereas you mention in the question nothing happens, but then again the question doesn't contain an actual repro so it's hard to tell where that difference lies.
So analytics.js asynchronously loads its self in the page. In the mean time it queues all calls to the API with a snub version of the object. Once analytics.js loads it executes all the calls in the queue. Then redefines its self, breaking all refs to the original window.analytics. So any calls that are encountered fast enough to My only work around for this is to make my exposer a function call that returns the current version of the window.analytics.
(function (ko, $, analytics) {
function sendTrack(event, props) {
analytics().track(event, props);
}
ko.bindingHandlers.segmentTrack = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = ko.unwrap(valueAccessor());
ko.applyBindingsToNode(element, { click: function () { sendTrack(value.event, value.options) }});
}
}
})(window.ko, window.jQuery, function () { return window.analytics; });

Creating a jQuery container to hold other functions

I am trying to create a simple class or a container to hold few JavaScript methods as shown below.
var Core = (function () {
var Error = {
alert: function() {
alert('Error => alert called');
},
display: function() {
alert('Error => display called');
}
};
var ajax = {
view: function(){
alert('Ajax => view called');
},
update: function(){
alert('Ajax => update called');
}
};
var call = function(){
Error.alert();
Error.display();
ajax.view();
ajax.update();
};
$(document).ready(function(){
call(); // This works fine.
}());
But for some reason I am not able to call these methods outside the container. For instance calling functions as shown below throws error.
$(document).ready(function(){
Core.Error.alert(); // This doesn't work.
Core.Call(); // This doesn't work.
});
Error: Uncaught TypeError: Cannot read property 'Error' of undefined
I can call the functions from within the container. I am new to the concept of jQuery plugins and would appreciate if someone can help me with this.
You can export these methods (read more about Module Pattern), like so
var Core = (function () {
...
return {
Error: Error,
Ajax: ajax,
Call: call
};
})();
Core.Error.alert();
Core.Call();
Example
Change it in:
var Core = {
error: {
alert: function () {
alert('Error => alert called');
},
display: function () {
alert('Error => display called');
}
},
ajax: {
view: function () {
alert('Ajax => view called');
},
update: function () {
alert('Ajax => update called');
}
},
call: function () {
Core.error.alert();
Core.error.display();
Core.ajax.view();
Core.ajax.update();
}
}
$(document).ready(function () {
Core.call(); // This works
}());
Working fiddle

How to put JavaScript DOM elements in object and access them?

I would like to place all of JavaScript DOM element queries in an object and access them throughout my script. Here's the current design pattern I'm using and I would like to stick to this format if possible:
(function ($) {
EXAMPLE = {
basicExample : function () {
config : {
logo : $('#logo'),
footer : $('footer'),
},
EXAMPLE.config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
}
EXAMPLE.basicExample();
})(jQuery);
Accessing the logo DOM element doesn't seem to work like this: EXAMPLE.config.logo
You did misplace the config part - not in your EXAMPLE object literal, but inside your basicExample function (where it acted as a labelled block statement with no-op expression statements inside, so it threw no error). Instead, it should be
(function ($) {
EXAMPLE = {
config : {
logo : $('#logo'),
footer : $('footer'),
},
basicExample : function () {
EXAMPLE.config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
}
};
EXAMPLE.basicExample();
})(jQuery);
However, you will need to place the initialisation into a DOM-ready handler, otherwise it might not find the elements. So either use
EXAMPLE = {
init : function($) {
EXAMPLE.config = {
logo : $('#logo'),
footer : $('footer'),
};
EXAMPLE.basicExample();
},
basicExample : function() {
this.config.logo.hover(function () {
jQuery(this).addClass('example');
}, function () {
jQuery(this).removeClass('example');
});
}
};
jQuery(EXAMPLE.init);
or just put everything in the handler, without any module pattern and extra basicExample function:
jQuery(function ($) {
var config = {
logo : $('#logo'),
footer : $('footer'),
};
config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
});
You are using object literal notation to define an object, and inside that object you define a constructor function, that needs to be used via new to be useful..I believe what you wanted is to create a namespace with a single object inside it.
try to remove the function and you should be able to access it, hence:
var EXAMPLE = {
basicExample : {
config : {
logo : $('#logo')
}
}
}
I would suggest declare a global object like this:
EXAMPLE = {
basicExample: function () {
this.config = {
logo: $('#logo'),
footer: $('footer')
};
return this;
},
applyHover: function () {
this.config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
}
};
And then call a .basicExample().applyHover() on document ready.
FIDDLE EXAMPLE
You have a comma at the end of the config.
config : {
logo : $('#logo'),
footer : $('footer'),
},
Should be:
config : {
logo : $('#logo'),
footer : $('footer')
},
You can do it like this:
var EXAMPLE = {
basicExample : {
config : {
logo : $('#logo')
}
}
}
EXAMPLE.basicExample.config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
JsFiddle
Or you can do what Artyom suggested.
EXAMPLE.basicExample is a function this is wrapping your config parameter. That is why it is not available to EXAMPLE.config. If you want the function EXAMPLE.basicEXAMPLE to define config as an element of EXAMPLE then do this:
EXAMPLE = {
basicExample : function () {
EXAMPLE.config = {
logo : $('#logo'),
footer : $('footer'),
},
EXAMPLE.config.logo.hover(function () {
$(this).addClass('example');
}, function () {
$(this).removeClass('example');
});
}
}

Categories

Resources