This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I'm using Vuejs and i would i have two methods one is to make a call and another one is to hangup
i would like to access to device variable that i have in makeCall methods from hangup
error : Cannot set property 'device' of undefined at eval
this is my code :
export default {
components: {Modal},
data: () => ({
device: '',
showModal: false,
form:{
output: ''
},
collection: {
}
}),
created(){
},
methods: {
init(){
this.showModal = true
},
dialer(digit){
this.form.output += `${digit}`
this.count++
},
clearScreen(){
let screen = document.getElementById('output').value
this.form.output = screen.slice(0, -1)
},
hangUp(){
this.device.disconnectAll();
},
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then(function (response) {
console.log("Got a token.");
console.log("Token: " + response.data.token);
// Setup Twilio.Device
this.device = new Twilio.Device(response.data.token, {
// Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
// providing better audio quality in restrained network conditions. Opus will be default in 2.0.
codecPreferences: ["opus", "pcmu"],
// Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
// but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
// a second time and sending the tone twice. This will be default in 2.0.
fakeLocalDTMF: true,
// Use `enableRingingState` to enable the device to emit the `ringing`
// state. The TwiML backend also needs to have the attribute
// `answerOnBridge` also set to true in the `Dial` verb. This option
// changes the behavior of the SDK to consider a call `ringing` starting
// from the connection to the TwiML backend to when the recipient of
// the `Dial` verb answers.
enableRingingState: true,
debug: true,
});
this.device.on("ready", function (device) {
console.log("Twilio.Device Ready!");
});
this.device.on("error", function (error) {
console.log("Twilio.Device Error: " + error.message);
});
this.device.on("connect", function (conn) {
console.log('Successfully established call ! ');
// $('#modal-call-in-progress').modal('show')
});
this.device.on("disconnect", function (conn) {
console.log("Call ended.");
// $('.modal').modal('hide')
});
var params = {
To: document.getElementById('output').value
};
console.log("Calling me " + document.getElementById('output').value + "...");
if (this.device) {
var outgoingConnection = this.device.connect(params);
outgoingConnection.on("ringing", function () {
console.log("Ringing...");
});
}
})
.catch(function (err) {
console.log(err);
console.log("Could not get a token from server!");
});
}
}
}
</script>
The error was due to how this works in JS. The function declaration in the promise was creating a different this context than the main function. The function keyword sets this based on where it is called, whereas arrow functions set this based on where it is defined in the code.
All you need to do is replace the function(response){} declaration in the getAPI promise .then with an arrow function, and it will work fine.
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then((response) => {
Try replacing these lines - to use an arrow function in the .then
Related
I'm using a Facebook login and I'm showing progress loading for the user until I get a response back from Facebook for authentication.
But I used to hide the progress bar like this.progress = false but this variable is undefined inside the window function.
My code :
initFacebook() {
this.progress=true
window.fbAsyncInit = function() {
window.FB.init({
appId: "MY-APP-ID", //You will need to change this
cookie: true, // This is important, it's not enabled by default
version: "v2.6",
status: false,
});
window.FB.login(function(response) {
if (response.status === 'connected'){
window.FB.api('/me?fields=id,name,email', function(response) {
console.log( response) // it will not be null ;)
})
} else {
console.log("User cancelled login or did not fully authorize.")
}
},
{scope: 'public_profile,email'}
);
this.progress = false
console.warn(this.progress)
};
},
I'm unable to set this.progress = false after getting all responses from Facebook.
I get an error while I console.log(this.progress) variable.
Error :
Login.vue?7463:175 undefined
How can I set this.progress variable to false once the authentication checks are complete?
Try converting all function() calls into arrow function calls () =>
The problem is that a function() will break the global vue scope. So vue this is not available within a function() call, but it is available within an arrow function () => {}
In a block scope (function() { syntax), this is bound to the nested scope and not vue's this instance. If you want to keep vues this inside of a function, use an arrow function (ES6) or you can have const that = this and defer the global this to that in a regular function() { if you prefer it this way.
Try using this code converted with arrow functions and see if it works:
initFacebook() {
this.progress=true
window.fbAsyncInit = () => {
window.FB.init({
appId: "MY-APP-ID", //You will need to change this
cookie: true, // This is important, it's not enabled by default
version: "v2.6",
status: false,
});
window.FB.login((response) => {
if (response.status === 'connected'){
window.FB.api('/me?fields=id,name,email', (response) => {
console.log( response) // it will not be null ;)
})
} else {
console.log("User cancelled login or did not fully authorize.")
}
},
{scope: 'public_profile,email'});
this.progress = false
console.warn(this.progress)
};
},
I know this because I just had the same problem :-) see here:
Nuxt plugin cannot access Vue's 'this' instance in function blocks
In the Azure B2C in the authCallback() the ItWillCallPromise is not getting called. Is it as per the design or I am doing something wrong. Also, if its not possible as per the design is there a workaround to call the ItWillCallPromise method ?
function initializeAuthAgent() {
var authConfig = Config();
authAgent = new Msal.UserAgentApplication({
auth: {
clientId: authConfig.clientId,
authority: authConfig.authority,
validateAuthority: false,
postLogoutRedirectUri: '/index.html'
},
cache: {
cacheLocation: 'sessionStorage'
}
});
authAgent.handleRedirectCallback(authCallback);
authCallback(){
ItWillCallPromise.then(function(ID){ console.log(ID)};
}
ItWillCallPromise = function(){
return fetch(url).then(function(a){ return a.ID;}
}
Not sure if it's a typo in your code snippet. But as per that, it's not getting called because you are not calling :). () is missing.
ItWillCallPromise().then(function(ID){ console.log(ID)};
In MSAL.js v1, handleRedirectCallback will only be invoked when there is a hash response in the url (as a result of invoking loginRedirect or acquireTokenRedirect). Depending on the business logic of your app, you can first check if there is a hash in the url (before instantiating UserAgentApplication, which will clear the hash if one was present) and then check if a user is logged in, and then invoke ItWillCallPromise directly.
For example:
function initializeAuthAgent() {
var authConfig = Config();
var hasHash = !!window.location.hash;
authAgent = new Msal.UserAgentApplication({
auth: {
clientId: authConfig.clientId,
authority: authConfig.authority,
validateAuthority: false,
postLogoutRedirectUri: '/index.html'
},
cache: {
cacheLocation: 'sessionStorage'
}
});
var isLoggedIn = !!authAgent.getAccount();
// If there is already a logged in user and were not returning from a redirect operation, immediately call ItWillCallPromise.
if (isLoggedIn && !hasHash) {
ItWillCallPromise()
}
authAgent.handleRedirectCallback(authCallback);
authCallback(){
ItWillCallPromise.then(function(ID){ console.log(ID)};
}
ItWillCallPromise = function(){
return fetch(url).then(function(a){ return a.ID;}
}
MSAL.js v2 (aka #azure/msal-browser on npm) makes this easier, as handleRedirectPromise (which replaces handleRedirectCallback) is invoked on every page load. More details: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/v1-migration.md
I am using the Taskrouter js library, more specifically the worker.js.
this.worker.on("reservation.created", (reservation) => {
reservation.accept()
});
However, I am getting an error saying that
accept() is not a function
According to the documentation here: https://www.twilio.com/docs/api/taskrouter/worker-js
This will accept the reservation for the worker.
Note: This will NOT perform any telephony. If the task was enqueued
using the Enqueue TwiML verb, utilize
reservation.dequeue(#reservation-dequeue) to perform telephony and
dequeue the call.
reservation.accept(
function(error, reservation) {
if(error) {
console.log(error.code);
console.log(error.message);
return;
}
console.log("reservation accepted");
for (var property in reservation) {
console.log(property+" : "+reservation[property]);
}
}
);
So we I am confused as reservation has no function accept(), but according to the documentation it does... So how do I accept a reservation from js?
Why do you have this.worker.on?
https://www.twilio.com/docs/api/taskrouter/worker-js#example_6
worker.on("reservation.created", function(reservation) {
console.log(reservation.task.attributes) // {foo: 'bar', baz: 'bang' }
console.log(reservation.task.priority) // 1
console.log(reservation.task.age) // 300
console.log(reservation.task.sid) // WTxxx
console.log(reservation.sid) // WRxxx
});
I'am trying to run a Skype SDK on my site, which will allow me to log into Skype initially. The code I'am using is from https://msdn.microsoft.com/EN-US/library/dn962162(v=office.16).aspx but when running the javascript through it complains of an undefined object. Here is the javascript code (ignore the $j, this is needed by us to run jQuery),
/**
* This script demonstrates how to sign the user in and how to sign it out.
*/
$j(function () {
'use strict'; // create an instance of the Application object;
// note, that different instances of Application may
// represent different users
var Application
var client;
Skype.initialize({
apiKey: 'SWX-BUILD-SDK',
}, function (api) {
Application = api.application;
client = new Application();
}, function (err) {
alert('some error occurred: ' + err);
});
// whenever state changes, display its value
client.signInManager.state.changed(function (state) {
$j('#application_state').text(state);
});
// when the user clicks on the "Sign In" button
$j('#signin').click(function () {
// start signing in
client.signInManager.signIn({
username: $j('#username').text(),
password: $j('#password').text()
}).then(
//onSuccess callback
function () {
// when the sign in operation succeeds display the user name
alert('Signed in as ' + client.personsAndGroupsManager.mePerson.displayName());
},
//onFailure callback
function (error) {
// if something goes wrong in either of the steps above,
// display the error message
alert(error || 'Cannot sign in');
});
});
// when the user clicks on the "Sign Out" button
$j('#signout').click(function () {
// start signing out
client.signInManager.signOut()
.then(
//onSuccess callback
function () {
// and report the success
alert('Signed out');
},
//onFailure callback
function (error) {
// or a failure
alert(error || 'Cannot sign in');
});
});
});
When I run this through, it doesn't enter into the "Skype.initialize({" code but jumps to "client.signInManager.state.changed(function (state) {", which is when it throws this error "Uncaught TypeError: Cannot read property 'signInManager' of undefined". When running this though the source debugger in chrome it shows that "Application" is undefined and that "client" is also undefined. So my question is why aren't these 2 objects getting initialised in the Skype.initialize code?
You will have to add the listener, after the client is initialized. So in the initialize "success" callback. The way you have it implemented at the moment, the script tries to add the listener before the client is initialized, on an undefined object attribute, hence the error.
I am trying to test the upload functionality using this guide with the only exception of using cfs-s3 package. This is very basic with simple code but I am getting an error on the client console - Error: Access denied. No allow validators set on restricted collection for method 'insert'. [403]
I get this error even though I have set the allow insert in every possible way.
Here is my client code:
// client/images.js
var imageStore = new FS.Store.S3("images");
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
Images.deny({
insert: function(){
return false;
},
update: function(){
return false;
},
remove: function(){
return false;
},
download: function(){
return false;
}
});
Images.allow({
insert: function(){
return true;
},
update: function(){
return true;
},
remove: function(){
return true;
},
download: function(){
return true;
}
});
And there is a simple file input button on the homepage -
// client/home.js
'change .myFileInput': function(e, t) {
FS.Utility.eachFile(e, function(file) {
Images.insert(file, function (err, fileObj) {
if (err){
console.log(err) // --- THIS is the error
} else {
// handle success depending what you need to do
console.log("fileObj id: " + fileObj._id)
//Meteor.users.update(userId, {$set: imagesURL});
}
});
});
}
I have set the proper policies and everything on S3 but I don't think this error is related to S3 at all.
// server/images.js
var imageStore = new FS.Store.S3("images", {
accessKeyId: "xxxx",
secretAccessKey: "xxxx",
bucket: "www.mybucket.com"
});
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
I have also published and subscribed to the collections appropriately. I have been digging around for hours but can't seem to figure out what is happening.
EDIT: I just readded insecure package and everything now works. So basically, the problem is with allow/deny rules but I am actually doing it. I am not sure why it is not acknowledging the rules.
You need to define the FS.Collection's allow/deny rules in sever-only code. These are server-side rules applied to the underlying Mongo.Collection that FS.Collection creates.
The best approach is to export the AWS keys as the following environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, remove the accessKeyId and secretAccessKey options from the FS.Store, and then move the FS.Collection constructor calls to run on both the client and server. The convenience of using env vars is mentioned on the cfs:s3 page
In addition to this you can control the bucket name using Meteor.settings.public, which is handy when you want to use different buckets based on the environment.