Strange behavior in javascript argument inside a global Object - javascript

there is a strange behavior in an argument inside a Global Javascript object:
I need to test my code with jasmine.js, but I canĀ“t pass the expected value to the argument always return undefined in jasmine test.
//My model
myGlobalObject = function(){
_myCart = function(){
return {
total : 0,
products : []
}
}
return {
init: function(strangeArgument){
console.log(strangeArgument) //this return undefined in jasmine test
},
myCart : _myCart,
addProduct : function(Products){
return _myCart()
},
.....
}
}
The test:
const c{
empty : {
total: {
beforeVAT: 0,
afterVAT: 0,
VAT: 0
},
products: []
}
}
beforeEach(() => {
this.instance = myGlobalObject();
this.instance.init();
this.productWithoutQuantity = Object.assign({}, _.productA);
delete this.productWithoutQuantity.quantity;
this.productWithQuantity = Object.assign({}, _.productB);
});
test(`the cart should be empty`, () => {
expect(this.instance.getCart()).toEqual(c.empty);
});
.... more tests
And my main js:
var e = myGlobalObject();
var initialState = function (){
return {
total: {
beforeVAT: 0,
afterVAT: 0,
VAT: 0
},
products: []
}
}
e.init(initialState);
What its wrong?

Although I fail to completely understand the intent of the OP here, following is my take on the question
_myCart can be a local variable because it doesn't seem to serve any greater purpose, atleast from the code provided by OP
The call to instance.init can be with empty parenthesis or with a legitimate variable- depends on what OP is trying to achieve here.
I've included both main.js code snippet as well as testVariable.instance.init(); (on a simple note its undefined if it is undefined anyway as commented by #Bergi)
See it in action here
myGlobalObject = function() {
this._myCart = function() {
return {
total: 0,
products: []
}
}
return {
init: function(strangeArgument) {
console.log(strangeArgument)
},
myCart: this._myCart,
addProduct: function(Products) {
return this._myCart()
}
}
}
var e = myGlobalObject();
var initialState = function() {
return {
total: {
beforeVAT: 0,
afterVAT: 0,
VAT: 0
},
products: []
}
}
e.init(initialState);
describe('ajax test suite', function() {
var testVariable = {}
var c = {
empty: {
total: 0,
products: []
}
}
beforeEach(function() {
testVariable.instance = myGlobalObject();
testVariable.instance.init("hello");
testVariable.instance.init();
});
it('the cart should be empty', function() {
expect(testVariable.instance.myCart()).toEqual(c.empty);
});
});

Related

Converting Calories Tracking application to ES6 Classes

I managed to recreate a MVC calorie tracker app from a course and I am trying to convert it to ES6 classes now.
I am a little stuck in understanding how to call the methods in the Module inside the Controller to return the items I need.
class Item {
constructor() {
this.data = {
items: [{
name: 'Salad',
calories: 200,
id: 0
},
{
name: 'Eggs',
calories: 500,
id: 1
}],
totalCalories: 0,
currentItem: null
}
};
getItems() {
return this.data.items
};
logData = () => {
console.log(data.items);
};
}
class App {
constructor(Item, UI) {
this.Item = Item;
this.UI = UI;
}
init() {
const items = Item.getItems();
UI.populateItemList(items)
}
}
const application = new App(new Item(), new UI())
When I try to call Item.logData() in the console it gives me TypeError: this.data is undefined.
I researched online and it seems that the method I declared is for the constructor only. How would I go about declaring methods that I'll use in the Controller or in any other class, just like I did below by returning a method out of the constructor?
What Im trying to convert initially looks like this:
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.name = name;
this.id = id;
this.calories = calories;
}
const data = {
items: StorageCtrl.getStorage(),
totalCalories: 0,
currentItem: null
}
return {
getItems: function () {
return data.items
},
logData: function () {
return data;
}
}
const App = (function (ItemCtrl, StorageCtrl, UICtrl) {
return {
init: function () {
const items = ItemCtrl.getItems();
UICtrl.populateItems(items);
}
}
})(ItemCtrl, StorageCtrl, UICtrl);
App.init();
You need to initialise the controller first:
class App {
constructor(Item, UI) {
this.item = new Item();
this.UI = new UI();
}
init() {
const items = this.item.getItems();
this.UI.populateItemList(items)
}
}

Typescript, problem with "this" inside arrow functions and rxjs

im trying to push to an array inside a subscrive method of rxjs using => but the variable that is an array outside changes into an object inside so i cannot use .push
#Component({
selector: 'devices_status-panel',
templateUrl: './devices.component.html',
styleUrls: ['./devices.component.scss']
})
export class DevicesComponent implements OnInit {
public rows = Array<any>();
public columns = [
{ date: 'Fecha' },
{ deviceId: 'Equipo' },
{ error: 'Estado' },
{ statusType: 'Evento'},
{ location: 'Localidad'},
{ ip: 'Ip' },
{ version: 'Version' },
{ unencriptedMessage: 'Mensaje'}
];
constructor(private devicesData: DevicesData) {
console.log("0")
console.log(this.rows)
this.getDeviceState();
}
getDeviceState(){
this.devicesData.getStatePipe()
.subscribe(([deviceState, info]) => {
console.log("1")
console.log(this.rows)
Object.keys(deviceState).forEach((key1) => {
const thisState: DeviceState = deviceState[key1];
console.log("2")
console.log(this.rows)
Object.keys(thisState.status).forEach((key2) => {
console.log("3")
console.log(this.rows)
const status: Status = thisState.status[key2];
if (status){
const eventGroupArray: Array<Array<DeviceEvent>> = status.deviceStatus;
eventGroupArray.forEach((eventArray) => {
eventArray.forEach((event) => {
const state: StateArray = {
date: event.date,
deviceId: event.deviceId,
error: status.error,
ip: event.ip,
statusType: event.statusType,
unencriptedMessage: event.unencriptedMessage,
version: event.version,
location: null
};
if (info.info[thisState.id]){
state.location = info.info[thisState.id];
}else{
state.location = "Desconocida"
}
console.log(this.rows)
console.log(typeof this.rows)
this.rows.push(state);
});
});
}
});
});
});
console.log(this.rows)
}
}
As you can see i added logs inside subscribe and just before the function call, this is an array outside and an object inside
I tried to solve it myself but i cant find where is the problem, any help is appreciated
Thanks
You haven't shown us what the log statements reveal, but if they show something different, the only reason that will happen is that something is assigning to this.rows between the time you log it prior to subscribing and the time the subscription happens, like this example using setTimeout:
const foo = {
example() {
this.rows = [];
console.log(1, this.rows);
setTimeout(() => {
console.log(2, this.rows);
}, 100);
}
};
foo.example();
foo.rows = {};
this inside the arrow function will be the same as it was outside, because that's how arrow functions work. So if this.rows is changing, it's because something is changing it.
It might be a closure problem. Try to add
getDeviceState(){
const _that = this;
.
.
.code...
_that.rows.push(state);
}

Vue Watch doesnt Get triggered when using axios

Hey guys I have this code that fetches data from database usin axios, and in the .then() function I set a data property, watch doesnt trigger. Here is some code that I currently have. And thank you in advance!
export default {
name: '..',
data() {
return {
autocompleteOn: false
}
},
watch: {
autocompleteOn(oldVal, newVal) {
console.log('autocomplet') // doesnt trigger this
}
},
methods: {
fetchAutocompleteResults: _.debounce((filter) => {
let $this = this;
let data = {
filter: filter,
page: $this.page
};
filter.resources.response = [];
filter.loading = true;
axios.post(BASE_URL + '/search/filter', data).then(function(response) {
if (response.data.length) {
filter.autocompleteOn = true;
$this.autocompleteOn = true;
filter.resources.response = filter.resources.response.concat(response.data);
$this.currentFilter = filter;
$this.page++;
console.log($this.autocompleteOn); // this is correct
}
filter.loading = false;
});
}, 300)
}
}
The debounce with an arrow function is making the this be something other than the Vue instance (e.g. window).
Instead of:
methods: {
fetchAutocompleteResults: _.debounce((filter) => {
Use:
methods: {
fetchAutocompleteResults: _.debounce(function (filter) {
// ^^^^^^^^ ^^^
Demo:
new Vue({
el: '#app',
data() {
return {
autocompleteOn: false
}
},
watch: {
autocompleteOn(oldVal, newVal) {
console.log('autocomplet') // doesnt trigger this
}
},
methods: {
fetchAutocompleteResults: _.debounce(function (filter) { // CHANGED from arrow function
let $this = this;
let data = {
filter: filter,
page: $this.page
};
filter.resources.response = [];
filter.loading = true;
// changed data for demo
data = [{title: 'foo', body: 'bar', userId: 1}];
// changed URL for demo
axios.post('https://jsonplaceholder.typicode.com/posts', data).then(function(response) {
if (response.data.length) {
filter.autocompleteOn = true;
$this.autocompleteOn = true;
filter.resources.response = filter.resources.response.concat(response.data);
$this.currentFilter = filter;
$this.page++;
console.log($this.autocompleteOn); // this is correct
}
filter.loading = false;
});
}, 300)
}
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
<div id="app">
<button #click="fetchAutocompleteResults({resources: {}})">fetchAutocompleteResults</button>
</div>

Elastic Search JS Function Return value

Question :
Why is the variable (resultVisitor) returning undefined?
When i log hits inside the function searchVisitors(), the log is returning an array of objects?
Any Ideas?
/* Get passanten telling */
var searchVisitorParams = {
index: 'veenendaal',
type: 'passanten',
size: 100,
body: {
fields: ["Tijdsperiode", "201_WE_Veenendaal", "940_HEMA_Veenendaal"],
query: {
"match_all": {}
},
sort: {
Tijdsperiode: "asc"
}
}
};
function searchVisitors() {
client.search(searchVisitorParams).then(function (body) {
var hits = body.hits.hits;
console.log(hits)
return hits;
});
}
var resultVisitor = searchVisitors();
console.log(resultVisitor)
Return is inside a callback function. I would do something like this:
/* Get passanten telling */
var searchVisitorParams = {
index: 'veenendaal',
type: 'passanten',
size: 100,
body: {
fields: ["Tijdsperiode", "201_WE_Veenendaal", "940_HEMA_Veenendaal"],
query: {
"match_all": {}
},
sort: {
Tijdsperiode: "asc"
}
}
};
function searchVisitors(callback) {
client.search(searchVisitorParams).then(function (body) {
var hits = body.hits.hits;
callback(hits);
});
}
searchVisitors(function(hits){ // Results are inside hits variable
console.log(hits);
// .... Your code ... //
});

KnockOutJS trigger parent function on child subscribe

I am currently trying to learn KnockOutJS. I thought it would be a great idea to create a simple task-list application.
I do not want to write a long text here, let's dive into my problem. I appreciate all kind of help - I am new to KnockOutJS tho!
The tasks are declared as followed:
var Task = function (data) {
var self = this;
self.name = ko.observable(data.name);
self.status = ko.observable(data.status);
self.priority = ko.observable(data.priority);
}
And the view model looks like this
var TaskListViewModel = function() {
var self = this;
self.currentTask = ko.observable();
self.currentTask(new Task({ name: "", status: false, priority: new Priority({ name: "", value: 0 }) }));
self.tasksArr = ko.observableArray();
self.tasks = ko.computed(function () {
return self.tasksArr.slice().sort(self.sortTasks);
}, self);
self.sortTasks = function (l, r) {
if (l.status() != r.status()) {
if (l.status()) return 1;
else return -1;
}
return (l.priority().value > r.priority().value) ? 1 : -1;
};
self.priorities = [
new Priority({ name: "Low", value: 3 }),
new Priority({ name: "Medium", value: 2 }),
new Priority({ name: "High", value: 1 })
];
// Adds a task to the list
// also saves updated task list to localstorage
self.addTask = function () {
self.tasksArr.push(new Task({ name: self.currentTask().name(), status: false, priority: self.currentTask().priority() }));
self.localStorageSave();
self.currentTask().name("");
};
// Removes a task to a list
// also saves updated task list to localstorage
self.removeTask = function (task) {
self.tasksArr.remove(task);
self.localStorageSave();
};
// Simple test function to check if event is fired.
self.testFunction = function (task) {
console.log("Test function called");
};
// Saves all tasks to localStorage
self.localStorageSave = function () {
localStorage.setItem("romaTasks", ko.toJSON(self.tasksArr));
};
// loads saved data from localstorage and parses them correctly.
self.localStorageLoad = function () {
var parsed = JSON.parse(localStorage.getItem("romaTasks"));
if (parsed != null) {
var tTask = null;
for (var i = 0; i < parsed.length; i++) {
tTask = new Task({
name: parsed[i].name,
status: parsed[i].status,
priority: new Priority({
name: parsed[i].priority.name,
value: parsed[i].priority.value
})
});
self.tasksArr.push(tTask);
}
}
};
self.localStorageLoad();
}
What I want to do in my html is pretty simple.
All tasks I have added are saved to localStorage. The save function is, as you can see, called each time an element has been added & removed. But I also want to save as soon as the status of each task has been changed, but it is not possible to use subscribe here, such as
self.status.subscribe(function() {});
because I cannot access self.tasksArr from the Task class.
Any idea? Is it possible to make the self.tasksArr public somehow?
Thanks in advance!
Try this:
self.addTask = function () {
var myTask = new Task({ name: self.currentTask().name(), status: false, priority: self.currentTask().priority() })
myTask.status.subscribe(function (newValue) {
self.localStorageSave();
});
self.tasksArr.push(myTask);
self.localStorageSave();
self.currentTask().name("");
};

Categories

Resources