saveEvent = (eventId, event) => {};
saveEvent(eventId, event);
What is wrong here? I think I defined clearly the method.
Use this keyword to access the class fields/properties and methods.
Example:
class SomeClass {
saveEvent = (eventId, event) => { };
someOtherFunction = () => {
this.saveEvent(eventId, event);
}
}
You missed to write this property and you are calling the saveEvent as a global function.
this.saveEvent(eventId, event)
If you're using OOP (classes) Then put the this keyword before executing the function
Like:- this.saveEvent(eventId, event). And if not, please post the complete code here but don't take a screenshot! And I'm glad to help you
Related
I am working on a task where I have an event listener window.addEventListener which is in javascript, based on event data I want to trigger a function of typescript and pass the data to that function. the point I am not getting is how to call typescript function in javascript. I have tried different things like a global variable, returning a value from js function but didn't work for me.
ngOnInit() {
(function ($) {
$(document).ready(function () {
window.addEventListener('message', function (event) {
console.log("Rece new Call event ibrahim " + JSON.stringify(event.data));
let obj: any = JSON.stringify(event.data)
obj = JSON.parse(obj);
console.log(obj)
if (obj.EventType === "handleContactIncoming") {
var num = obj.Number
// here i want to trigger Typescript function and pass this num to that function.
}
else if (event.data === "endCall") {
// return "No"
// var dbBtn = document.getElementById("db");
// dbBtn.click();
}
// $('.sidebar-menu').tree();
});
});
});
There is no difference when calling function from TS or JS. Finally there's always only JS in the browser, TS exists only in source code.
Also your code is a bit messy. There's no need to use jQuery inside angular (with an exception when you want to use some plugins or custom controls).
$(document).ready(function () {
is also redundant, if angular works the document is for sure ready.
Your code is quite messy and breaks separation of concerns. You should not use jQuery inside Angular. The injectable EventManager provides functionality for setting events on the window or document objects.
constructor(private readonly eventManager: EventManager) {}
ngOnInit(): void {
this.eventManager.addGlobalEventListener(target, event, () => {
this.hello();
});
}
hello(): void {
console.log('Hello World!');
}
I am trying to make my code shorter and more optimized, and want to make it look clearer.
So far I did this :
function id(a) {
return document.getElementById(a);
}
function cl(a) {
return document.getElementsByClassName(a);
}
function tg(a) {
return document.getElementsByTagName(a);
}
function qs(a) {
return document.querySelector(a);
}
function qa(a) {
return document.querySelectorAll(a);
}
Now I have the possibility to call qs("#myElement"). Now I want to attach a event to the specified element just like qs("#myElement").addEventListener("click", callBack). It works great for me. But when I try to make this :
function ev(e, call) {
return addEventListener(e, callback);
}
And then try to call qs("#init-scrap").ev("click", someFunction) then it pops up the following error :
Uncaught (in promise) TypeError: qs(...).ev is not a function.. I don't know what is the problem, do I have to try method chaining ? or any other way I can resolve this problem.
Note : I don't want to use any libraries or frameworks liek Jquery etc.
If you wish to use syntax qs("#init-scrap").ev("click", someFunction), you need to wrap object returned by querySelector into another object that has ev function.
class jQueryLite {
constructor(el) {
this.el = el;
}
ev(e, callback) {
this.el.addEventListener(e, callback);
return this;
}
}
qs(a) {
return new jQueryLite(document.querySelector(a));
}
It's called Fluent interface, if you wish to look it up.
Just pass the element/nodelist in as the first argument and attached the listener to it.
function ev(el, e, call) {
return el.addEventListener(e, callback);
}
As an alternative, but not something I would recommend, you could add ev as a new Node prototype function:
function qs(selector) {
return document.querySelector(selector);
}
if (!Node.prototype.ev) {
Node.prototype.ev = function(e, cb) {
return this.addEventListener(e, cb);
};
}
qs('button').ev('click', handleClick);
let count = 0;
function handleClick() {
console.log(count++);
}
<button>Count+=1</button>
Note I've only tested this with document.querySelector. You might have to alter the code to work with document.querySelectorAll etc as they don't return single elements.
There is an error in your ev method. It should be
const ev = document.addEventListener.bind(document);
So instead of creating new functions that wrap the original, you can alias the actual function itself.
You should do the same for your other aliases if you want to go with this approach.
const qs = document.querySelector.bind(document);
const qa = document.querySelectorAll.bind(document);
My final word of advise would be to not alias these methods at all. The abbreviated method names hurt the readability of your code. Readability almost always trumps brevity as it comes to code.
I looked into the previous answers as an inspiration and created my take on it.
Core
const $ = (selector, base = document) => {
return base.querySelector(selector);
};
Node.prototype.on = function(type, listener) {
return this.addEventListener(type, listener);
};
It supports a base value in case you have another element than document but it's optional.
I like $ and on so that's what I use, just like jQuery.
Call it like below
$('button').on('click', (e) => {
console.log(e.currentTarget);
});
I'm using jQuery for some things in my angular2 projects. But I can't manage to use variables I've declared in angular2 to use in jQuery. I have something like this:
export class AddExerciseComponent implements OnInit {
parameters:Array<string> = ["FU"];
constructor() { }
ngOnInit() {
$('.chips').on('chip.add', function(e, chip){
this.parameters.push(chip.data);
console.log(this.selectedValue);
});
}
This would get me an error that parameters is not defined. I guess it's because I use this. What else can I do?
You need to use an arrow function expression (() => {}) to keep this in scope. Try:
export class AddExerciseComponent implements OnInit {
parameters:Array<string> = ["FU"];
constructor() { }
ngOnInit() {
// removed function keyword and added () => {} syntax
$('.chips').on('chip.add', (e, chip) => {
this.parameters.push(chip.data);
console.log(this.selectedValue);
});
}
When you passed your callback as a regular old function, JavaScript doesn't consider your callback to be within the scope of the calling function, leaving this unusable for calling data from the scope you thought you were in. By using an Arrow function, the scope is saved and this is usable for accessing data as expected.
If you are looking to use angular variables in jquery animate ON-Complete function call back,that's how you do it:
$('#myDiv').animate({top: 70+"%"},{
queue: false,
duration: 1000,
complete: () => {
//this is you angular variable of the class
this.angularVar = 0;
$("#myDiv").hide();
//this is you angular variable of the class
this.showAnimation = false;
//this is you angular class function
this.angularFunction();
console.log("animation complete");
}
});
Assign angular's this(instance) to Jquery's this(instance) to use the angular variable inside JQuery
let jQueryInstance = this; // This line will assign all the angular instances to jQueryInstance variable.
$('.chips').on('chip.add', (e, chip) => {
/* this.parameters.push(chip.data); */
// Instead of the above line we have to use like below
jQueryInstance.parameters.push(chip.data); // instead of "this", "jQueryInstance" is used
// console.log(this.selectedValue);
console.log(jQueryInstance.selectedValue);
});
I would like to get some help debugging a situation where a Reactive Variable is undefined, when it has been defined already.
This code is attaching a Reactive Variable to the template instance, and using the variable in template.autorun().
Template.home.onCreated(function () {
this.limit = new ReactiveVar(15);
this.autorun(function () {
this.subscribe('recent-topics', this.limit.get());
});
});
When I load the template for the first time, I expect the template to subscribe to recent-topics with an argument 15. However, the code throws an error:
Uncaught TypeError: Cannot read property 'get' of undefined
Any ideas why?
Just an answer for the sake of spreading the joys of ES6:
Template.home.onCreated(function () {
this.limit = new ReactiveVar(15);
this.autorun(() => {
this.subscribe('recent-topics', this.limit.get());
});
});
Make sure you add the grigio:babel package, and your Javascript file ends in .es6.js, .es6, or .jsx.
Explanation
In ES6 (aka ECMAScript 6), there's a new "fat arrow" syntax which is very similar to CoffeeScript's implementation. In ES6, when you do something like this:
someFunc = function () {
anotherThing((var1, var2) => {
this.thing = true;
});
};
It's the same as doing this:
someFunc = function () {
var self = this;
anotherThing(function (var1, var2) {
self.thing = true;
});
};
This is a scoping issue.
Inside of your Tracker.autorun, this no longer refers to the template, but the autorun's callback function. Inside of the autorun, try calling Template.instance().limit.get().
Better than using Template.instance().limit.get() (ryan's answer)
You should do something like this:
Template.home.onCreated(function () {
var self = this;
self.limit = new ReactiveVar(15);
self.autorun(function () {
self.subscribe('recent-topics', self.limit.get());
});
});
Say I'm using a library with the code that looks like below:
(function($)
{
function Library(el, options)
{
return new Library.prototype.init(el, options);
}
Library.fn = $.Library.prototype = {
init: function(el, options) {
this.$elm.on('keydown.library', $.proxy(this.keydown.init, this));
}
keydown: function() {
return {
init: function(e) {
... somecode
},
checkStuff: function(arg1, arg2) {
...someCode
}
}
};
}
})(jQuery);
It has a plugin system that provides access to this where this is an Object {init: function, keydown: function...}. I want to override the keydown.init function. Normally I could see using something like _.wrap to do it:
somefunc = _.wrap(somefuc, function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});
but that doesn't seem to work on the returned nested method e.g.:
this.keydown.init = _.wrap(this.keydown.init, function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});
The question might be answered on here but I don't really know the right words to use to describe this style of coding so its hard to search. Bonus points if you let me know if it is even correct to call it a nested returned method?
This pattern is called a module. The best thing you can do here is cache the method you want to override and call the cached method inside your override:
somefunc._init = somefunc.init;
somefunc.init = function () {
doStuff();
this._init();
};
I checked _.wrap and it does the same thing, what your missing as pointed out by another answer is you're losing the context of somefunc. In order to prevent that you can do:
somefunc.init = _.wrap(_.bind(somefunc.init, somefunc), function (oldRef, args) {
doStuff();
oldRef.call(this.args);
});
You will need to decorate (read: wrap) the keydown function so that you can wrap the init method of the object it returns:
somefunc.keydown = _.wrap(somefunc.keydown, function(orig) {
var module = orig(); // it doesn't seem to take arguments or rely on `this` context
module.init = _.wrap(module.init, function(orig, e) {
donewstuff();
return orig.call(this, e);
});
return module;
});
The problem is that your method is run out of context.
You need to set its this context (use .bind() for this)
somefunc.init = _.wrap(somefuc.init.bind(somefunc), function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});