Functions in React: my function isn't working, because of 'read-only' error. Why? - reactjs

I'm trying to write a function into a React component, but I am stuck with this error:
Uncaught Error: Module build failed: SyntaxError: "productMap" is read-only
Why is this happening? And how can I fix this, so I can use productMap?
Here is my function:
printReceipt() {
var products = this.props.updateBasket.products;
//create a map of products
const productMap = {};
for(let product of products) {
if(!productMap[product.id]) {
productMap[product.id] = 1;
} else {
productMap = productMap + 1;
}
}
console.log(productMap);
}

This is happening because poductMap is of type const and const cannot change through reassignment
Change it to a let or var instead
printReceipt() {
var products = this.props.updateBasket.products;
//create a map of products
let productMap = {};
for(let product of products) {
if(!productMap[product.id]) {
productMap[product.id] = 1;
} else {
productMap = productMap + 1;
}
}
console.log(productMap);
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

Use let productMap={}; instead of const.
The const declaration creates a read-only reference to a value.
Reference

use ()=> FunctionName() instead of FunctionName()
When we call the function FunctionName(), it is just executed, but when we write () => FunctionName(), then it is only called when that particular operation is performed for example onPress.
FunctionName() sometimes doesn't work, and is only read-only, using () => FUnctionName, is a good way.

Related

CanJS - Incorrect list objects type after mapping

If I have this instantiation const someObj = new MyObj({...someParams}) and MyObj is defined this way:
MyObj = DefineMap.extend("MyObj", {
myProp: {
Type: AnotherType.List
}
})
and
AnotherType.List = CanList.extend("AnotherType.List", {
Map: AnotherType
}, {
serialize() {
const res = [];
for (let i = 0; i < this.attr("length"); i++) {
res.push(this.attr(i.toString()).serialize());
}
return res;
}
})
then the someObj.myProp[0] type is DefineMap instead of AnotherType. How can I fix this?
I already tried this but still not working: const someObj = canReflect.assignDeep(new MyObj(), {...someParams})
With the help of Bitovi community I solved it (thanks to Brad Momberger).
So Brad explained that it happens because of the DefineList's bubble binding and the same doesn't happen with DefineMap objects.
So we always need to serialize the lists first the get the correct type of the list entries at the end, like this:
const someObj = new MyObj({
...someParams,
myProp: someParams.myProp.serialize()
})
You can see the full explanation here.

Typescript: Array is empty after calling and passing it to function

Hi I am building function to recursively "denest" a object of following interface:
export interface IUnit {
code: string
artifacts: IArtifact[]
units: IUnit[]
}
The idea is that I have a separate array that I returns with every immersion and after each return the returned array is "pushed" to local array and so on...
the function is as following:
const denestList = async (incomingUnit: IUnit): Promise<{ allUnits: IUnit[], allArtifacts: IArtifact[] }> => {
var units = [incomingUnit];
var artifacts = [...incomingUnit.artifacts];
//Array is full
console.log(unit.units)
//Array is empty
console.log(unit.units.length)
console.log([...unit.units])
console.log(Array.from(unit.units)?.length)
for (unit of incomingUnit.units) {
console.log(unit.code)
//Recursion happens here.
var result = await denestList(unit)
units.push(...result.allUnits)
artifacts.push(...result.allArtifacts)
}
return { allUnits: units, allArtifacts: artifacts }
}
The problem is that for (unit of incomingUnit.units) never happens. When I log unit.units it shows array full of IArtifact[], but when I run console.log(unit.units.length) it return 0.
Here is how to "denestList" function is called:
useEffect(() => {
asyncStart(unit)
}, []);
const asyncStart = async (mainUnit: IUnit) => {
var result = await denestList(mainUnit);
setAllUnits(result.allUnits)
setAllArtifacts(result.allArtifacts)
}
I would really appreciate any help. Thank you in advance

How to check whether array includes certain value google Apps Script

I'm using range.getValues() to load an array in Google Apps Script.
I want to loop through the array and do something if the array includes the value I'm looking for.
if (array.include("abc")){*doSomething*}
The problem is when I use this method, the array contain another arrays, so array.include() doesn't work.
I can use a workaround like this:
for (var i = 0; i<=array.length; i++){
if (array[i] == "abc"){*doSomething*}
I wonder are there a better way to do it?
I tried to use array.indexOf() but it returns -1 for 0th value, which is weird
function find() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const haystack=sh.getDataRange().getValues();
const needle="44";
let found = false;
haystack.forEach(r=>{
r.forEach(c=>{
if(c==needle) {
found=true;
}
})
});
if(found) {
SpreadsheetApp.getUi().alert('Needle was found in haystack');
}
}
or
function find() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const haystack=sh.getDataRange().getValues();
const needle="44";
let found = false;
haystack.forEach(r=>{
if(~r.indexOf(needle)) {
found=true;
}
});
if(found) {
SpreadsheetApp.getUi().alert('Needle was found in haystack');
}
}
Recommendation:
Alternatively, you can also try this way:
function arrayCheck(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var arr = ss.getDataRange().getValues(); //Get all values from sheet
Logger.log(arr);
arr.forEach(function(res) {
if(res == 'abc'){
Logger.log("Found a match");
//do something
}else{
Logger.log(res+" does not match abc");
}
});
}
Here's a sample sheet where I've got all the array values from:
Here's the result:

Why this setState is not a function in ComponenDidMount?

I am trying to fetch ordered data from Firebase and set it to state highscoreArray but it gives error "undefined is not a function (evaluating 'this.setState({ highscoreArray:sortedHighscores })')
componentDidMount() {
const reference = database.ref("highscores");
// Pushing sorted data to highscoreArray.
reference.orderByChild("highscore").limitToLast(3).on("value", function (snapshot) {
sortedHighscores = [];
snapshot.forEach(function (child) {
sortedHighscores.push({
"username": child.val().username,
"score": child.val().highscore
});
});
sortedHighscores = sortedHighscores.reverse();
console.log("sortedh", sortedHighscores); // fetch success
this.setState({highscoreArray: sortedHighscores}); // gives error
});
}
One of the major advantages of arrow functions is that it does not have it's own this value. It's this is lexically bound to the enclosing scope.
class Logger {
dumpData(data) {
var _this = this;
// this dumps data to a file and get the name of the file via a callback
dump(data, function (outputFile) {
_this.latestLog = outputFile;
});
}
}
// using arrow functions
class Logger {
dumpData(data) {
dump(data, outputFile => this.latestLog = outputFile);
}
}
1.this not accessible within loop so use variable let that = this the use that wherever you need this in this function.
componentDidMount() {
const reference = database.ref("highscores");
let that = this // here your variable declaration
// Pushing sorted data to highscoreArray.
reference.orderByChild("highscore").limitToLast(3).on("value", function (snapshot) {
sortedHighscores = [];
snapshot.forEach(function (child) {
sortedHighscores.push({
"username": child.val().username,
"score": child.val().highscore
});
});
sortedHighscores = sortedHighscores.reverse();
console.log("sortedh", sortedHighscores); // fetch success
that.setState({highscoreArray: sortedHighscores}); // gives error
});
}
Hope this will help you :) happy coding!
Inside the function callback the this has a different context. Either use an arrow function, or store a reference outside:
Arrow:
reference.orderByChild("highscore").limitToLast(3).on("value", (snapshot) => { ... });

Angular service not assigning value to empty object

I have a service:
storeApp.service('currentCustomer',function($http) {
this.customerID = 0;
this.customerInfo = {}
this.customerAttributes = {}
this.getCustomerInfo = function () {
if (this.customerID != 0) {
$http.get('/customers/' + this.customerID).
then(function (result) {
this.customerInfo = result.data[0]
})
}
}
and a controller:
storeApp.controller('storeList',function($scope,$http,currentCustomer) {
$scope.changeCust = function changeCust(id) {
currentCustomer.customerID = id;
currentCustomer.getCustomerInfo()
console.log("After Change customer:")
console.log(currentCustomer)
}
$scope.selectedStore = currentCustomer
});
If I try to access selectedStore.customerID, I get values.
If I try to access selectedStore.customerInfo, I get an empty array, even though when i put console logging in to check the values, it says they are assigned.
Any ideas what I'm doing wrong? Thanks everyone.
You are manually assigning a value to CustomerId, and your service method is assigning a value to customerInfo. Except this in the service method, is not the same as this in the service. You should instantiate a var self = this; reference inside the service and use this value in all your object manipulation. eg: self.customerInfo = ....
Your reference for this has been changed inside function. first store this reference in some variable and then assign properties, some prefer to use the word self but I prefer service
storeApp.service('currentCustomer',function($http) {
var service = this;
service.customerID = 0;
service.customerInfo = {}
service.customerAttributes = {}
service.getCustomerInfo = function () {
if (service.customerID != 0) {
$http.get('/customers/' + this.customerID).
then(function (result) {
service.customerInfo = result.data[0]
});
}
}

Resources