Javascript How to call another function within a variable object function [duplicate] - javascript

This question already has answers here:
How to call another function within the same object?
(2 answers)
Closed 4 years ago.
i want to call the isAuthenticated() method within the logout function.
(Im not sure what you call this layout its like a variable object containing functions)
var svc = {
logout: function () {
isAuthenticated() // Call isAuthenticated function here
},
login: function () {},
isAuthenticated: function () {}
}
Simply calling isAuthenticated() does not work.

svc is an object, where are logout & isAuthenticated are methods.You can use this to call the function.Here this points to the svc object
var svc = {
logout: function() {
this.isAuthenticated() // Call isAuthenticated function here
},
login: function() {
},
isAuthenticated: function() {
console.log('isAuthenticated called');
}
}
svc.logout()

Add this to it.
var svc = {
logout: function () {
this.isAuthenticated() // Call isAuthenticated function here
},
login: function (){
},
isAuthenticated: function () {
console.log("Test");
}
}
svc.logout();

I believe what you are looking for is:
this.isAuthenticated();
You need to use "this" to call other members of the same object.

Javascript object variables and functions are accessed by prefixing the object name followed by the variable/function name.
In your case, you can call isAuthenticated() like this:
svc.isAuthenticated()

You nee to use the reference of that object svc --> this.isAuthenticated()
var svc = {
logout: function() {
this.isAuthenticated()
},
login: function() {},
isAuthenticated: function() {
console.log("Is Authenticated!?")
}
}
svc.logout();
Another alternative is creating a function and declaring a variable, this way you will be able to call it directly as follow:
var svc = function() {
var isAuthenticated = function() {
console.log("Is Authenticated!?");
}
this.isAuthenticated = isAuthenticated;
this.logout = function() {
isAuthenticated()
};
this.login = function() {};
}
new svc().logout();
new svc().isAuthenticated();

Related

VueJS returns undefined in created function [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
i have started working on a small project using VueJs, i've made a get request using Axios library which returns some data as expected, but I cannot call loadUsers function using this inside mounted
this is my code:
export default{
data(){
return {
users : {}
}
},
methods:{
addCustomer(){
//var form = document.querySelector('#add-customer');
var formData = $('#add-customer').serialize();
axios.post('/Thirdparty', formData).then(function(response){
helper.validation(response.data);
//alert(response.data.error);
});
},
loadUsers(){
axios.get('/Thirdparty/loadUsers').then(function(data){
this.users = data.data;
});
}
},
created(){
let self=this
self.loadUsers();
}
}
as you can see also i've used self variable to call my loadUsers() function, but i'm still getting
this is undefined error
You're referencing this.users within the callback to axios.get().then() in loadUsers(). Due to you're using a standard function and not an arrow function, this is not referring to the Vue instance, i.e. the scope for this is now incorrect. Either use an arrow function or change the reference:
// Do this...
export default{
data(){
return {
users : {}
}
},
methods:{
addCustomer(){
//var form = document.querySelector('#add-customer');
var formData = $('#add-customer').serialize();
axios.post('/Thirdparty', formData).then(function(response){
helper.validation(response.data);
//alert(response.data.error);
});
},
loadUsers(){
axios.get('/Thirdparty/loadUsers').then((data) => { // Using an arrow function.
this.users = data.data;
});
}
},
created(){
let self=this
self.loadUsers();
}
}
// Or this...
export default{
data(){
return {
users : {}
}
},
methods:{
addCustomer(){
//var form = document.querySelector('#add-customer');
var formData = $('#add-customer').serialize();
axios.post('/Thirdparty', formData).then(function(response){
helper.validation(response.data);
//alert(response.data.error);
});
},
loadUsers(){
let self=this; // Adding "self"
axios.get('/Thirdparty/loadUsers').then(function(data){
self.users = data.data; // Referencing "self" instead of "this".
});
}
},
created(){
let self=this
self.loadUsers();
}
}

Access component data in Created or Mounted hook

I'm writing a component for Vue.js and I need to modify data on event. But for some reason, when I access it, it's set as undefined
module.exports = {
data: function() {
return {
visible: true
}
},
mounted: function() {
this.eventHub.$on('minimize', function(window_id) {
console.log(this.visible);
this.visible = !this.visible;
});
},
props: ["windowId"]
}
When the event is called for the first time, data.visible is undefined, for some reason.
Is there anything I'm doing wrong?
Thanks!
Because function (window_id) has it's own scope, you can not access this.
This can be solved by adding self = this.
let self = this
this.eventHub.$on('minimize', function(window_id) {
console.log(self.visible);
self.visible = !self.visible;
});
As Nick Rucci pointed out, you can also use an arrow function, and get rid of self = this.
this.eventHub.$on('minimize', (window_id) => {
console.log(this.visible);
this.visible = !this.visible;
});

cant update jasmine spy

Hi I have a Angular service that uses another service that loads data from the local storage on init.
angular
.module('app')
.factory('localStorage', function ($window)
{
if (!$window.localStorage)
{
// throw Error
}
return $window.localStorage;
});
angular
.module('app')
.factory('session', function (localStorage)
{
var container = JSON.parse(localStorage.getItem('sessionContainer'));
return {
getUser: getUser
};
});
Now i want to test the session service.
describe('SessionService', function ()
{
var service;
var localStorageMock;
// Load the module.
beforeEach(module('appRegistration'));
// Create mocks.
beforeEach(function ()
{
logMock = {};
localStorageMock = jasmine.createSpyObj('localStorageServiceMockSpy', ['setItem', 'getItem']);
localStorageMock.getItem.and.returnValue('{}');
module(function ($provide)
{
$provide.value('localStorage', localStorageMock);
});
inject(function (_session_)
{
service = _session_;
});
});
it('should call `getItem` on the `localStorageService` service', function ()
{
expect(localStorageMock.getItem).toHaveBeenCalledWith('sessionContainer');
});
describe('getUser method', function ()
{
it('should return an empty object when the user is not set', function ()
{
var result = service.getUser();
expect(result).toEqual({});
});
it('should return the user data', function ()
{
// localStorageMock.getItem.and.returnValue('{"user":{"some":"data"}}');
var result = service.getUser();
expect(result).toEqual({some: 'user data'});
});
});
});
As you can see in the should return the user data section.
I need a way to update the container so getUser returns the expected data.
I tried to update the getItem spy, but this does not work. The localStorageMock is already injected in the session service when i want to change the spy.
Any help?
The most simple way is to have a variable with mocked value that is common for both function scopes:
var getItemValue;
beforeEach({
localStorage: {
getItem: jasmine.createSpy().and.callFake(function () {
return getItemValue;
}),
setItem: jasmine.createSpy()
}
});
...
it('should return the user data', function ()
{
getItemValue = '{"user":{"some":"data"}}';
inject(function (_session_) {
service = _session_;
});
var result = service.getUser();
expect(result).toEqual({some: 'user data'});
});
Notice that inject should be moved from beforeEach to it for all specs (the specs that don't involve getItemValue may use shorter syntax, it('...', inject(function (session) { ... }))).
This reveals the flaw in service design that makes it test-unfriendly.
The solution is to make container lazily evaluated, so there is time to mock it after the app was bootstrapped with inject:
.factory('session', function (localStorage)
{
var containerCache;
function getUser() {
...
return this.container;
}
return {
get container() {
return (containerCache === undefined)
? (containerCache = JSON.parse(localStorage.getItem('sessionContainer')))
: containerCache;
},
getUser: getUser
};
});
Additionally, this makes possible to test session.container as well. In this case localStorageMock.getItem spy value may be redefined whenever needed.

Should my factory return an object with helper methods or should I use prototype?

I'm a beginner with angular and I try to understand if I should user a factory like that:
app.factory('FoobarServices', ['$http', function ($http) {
var Foobar = {
// Model
};
return {
getFoobar: function () {
},
setFoobar: function (Foobar) {
},
update: function (foobar) {
},
delete: function (id)
}
};
}]);
Or something like:
app.factory('Fooba', ['$http', function($http) {
function Foobar(foobar) {
// Initialize foobar
};
Foobar.prototype = {
getFoobars: function() {
},
setFoobar: function(foobar) {
},
update: function(foobar) {
},
delete: function(id) {
},
};
return Foobar;
}]);
I'm not sure to understand what's the pros and cons of each pattern, and which one is more suitable for an angular project.
Could you please tell me which one should I use?
It depends on how you want to use your service.
Factory is usually being used to store some constructor from which you can later instantiate some objects.
For example:
app.factory('Client', function () {
function Client (name) {
this.name = name;
}
Client.prototype.sayHello = function () {
console.log('Hello, my name is ' + this.name + '!');
}
return Client;
})
.controller('ClientController', function (Client) {
var bob = new Client('Bob');
})
If your service is singleton, you can register it as service instead of factory and angular will create an instance for you.
Or you can register it as factory but return some object with methods. It is useful when you don't want to deal with context (this) inside your service logic:
app.factory('ClientStorage', function () {
function set () {
// to be implemented
}
function get () {
// to be implemented
}
return {
get: get,
set: set
};
})

AngularJS Factory variable value assignment breaks binding

It seems that when I assign a new value to a variable in my service/factory it breaks the binding and the controller stops updating the value UNLESS I call the $scope.verify function in my controller which merely prints the service object to the console, then the binding updates once. Am I assigning the value wrong in the skypeClient factory?
property.changed(function (_status) {
state = _status;
console.log("New State" + state);
});
Ex. I execute $scope.signIn() and and the binding updates to signingIn but when the value changes to SignedIn (verified with console) the controller doesnt update to SignedIn unless I execute $scope.verify() for every change in skypeClient.state from there on after.
See code below:
Controller
controller('loginCntrl', function ($scope,skypeClient) {
$scope.skypeClient = skypeClient;
$scope.signIn = function () {$scope.skypeClient.signIn($scope.user, $scope.password)}
$scope.signOut = function(){$scope.skypeClient.signOut()}
$scope.verify = function () {
console.log(skypeClient);
console.log($scope.skypeClient);
}
});
Service
.factory('skypeClient', function () {
//Service Properties
var client = new Skype.Web.Model.Application;
var state = 'SignedOut';
var property = property = client.signInManager.state;
//Initialize Listeners
var init = function () {
client.signInManager.state.when('SignedIn', function () {
console.log('Signin:' + state); // This outputs the correct value
});
property.changed(function (_status) {
state = _status; //<--WHERE VALUE IS UPDATED
console.log("New State" + state);
});
}
//Signin Function
var signIn = function (username, password) {
client.signInManager.signIn({
username: username,
password: password
}).then(function () {console.log('LoggedIn');});
}
var signOut = function () {
client.signInManager.signOut()
.then(function () {
this.isSignedIn = false;
}, function (error) {
this.erros.push(error);
this.errorCount++;
});
}
init();
return {
signIn: signIn,
signOut, signOut,
state: function(){return state}
}
});
HTML
(Current Signin State: {{skypeClient.state()}} )
Let me try this out.
If you can, try to make the state a variable on the scope where it needs to show up in the binding.
Controller
controller('loginCntrl', function ($scope,skypeClient) {
...
$scope.state = skypeClient.state();
...
});
HTML
(Current Signin State: {{ state }} )
Now, in your controller, you can add a $watch to the state variable from the skypeClient. If I'm correct, things should update with much more success.
Controller (again)
controller('loginCntrl', function ($scope,skypeClient) {
...
$scope.state = skypeClient.state();
...
// Add this $watch
$scope.$watch(skypeClient.state, function (newValue, oldValue) {
if (newValue !== oldValue) {
$scope.state = newValue;
}
});
});

Categories