Typescript: Typescript loop showing undefined - angularjs

public Update() {
this.Data = this.Items;
console.log(this.Data);
for (let value of this.Data) {
console.log(value);
}
}
console
[Object, Object, Object]
Object
CandidateName:"B"
ControlId:0
CreatedBy:null
CreationDateTime:null
ExamId1:2000
ExamName:" Safety"
Id:1292353
after last object it showing length:3
when i going to loop over this object,it is throwing error length is undefined,please help me.

If I understand correctly, this.Items is probably undefined in some cases and you cannot iterate.
So:
for (let value of (this.Data || [])) {
This guards against bad values

The for in or for of statement should be avoided for iterating over arrays. It has two "drawbacks":
1) The order is not guarantee
2) Also inherited properties will be listed/enumerated, if enumerable:false is not specified when defining the property.
If for example you add a property to your prototype, this loop will iterate also over that one.
Array.prototype.test = "test";
var a = ['a', 'b'];
for (let i in a) {
console.log(a[i]);
}
for (let i of a) {
console.log(i);
}
You should see also your property printed.
If you change your loop into a sequential for loop:
for (let i = 0; i < this.Data.length; i++ value of this.Data) {
console.log(this.Data[i]);
}
or a:
this.Data.forEach((el) => {
console.log(el);
});
you may not see your issue.

If you want to iterate over objects, You must use Object.keys(your_obj). Because object doesn't have length property. You can iterate through only of type 'Array' or 'String' using for of. You can use Object.keys(your_obj).length for sequential for loop for(var i=0; i<Object.keys(your_obj).length; i++)
public Update() {
this.Data = this.Items;
console.log(this.Data);
for (let obj of this.Data) {
console.log(obj);
//iterate over object here
for(let property of Object.keys(obj)){
// write your logic for specific object
}
}
}
Extension to quirimmo's answer, sequential for loop, use this
this.Data.forEach(function(obj){
console.log(obj);
//iterate over object here
for(var i=0; i<Object.keys(obj).length; i++){
// write your logic for specific object
}
})

Related

Skipping loop iterations based on type?

I have an array of both objects (JSX elements) and strings, which I want to iterate over and perform logic on the items that are strings, but skip the objects.
const array= ['string', {...}, {...}, 'string', 'string', {...}];
for (let i = 0; i < array.length ; i++) { if( {/* This is an object */} ){continue;}else{
{/* perform logic */}}
Is is possible to continue a loop based on type?
The typeof operator should do what you want. However, if the logic you wish to perform only works on strings then you may want to consider inverting your logic to guard against the potential for your array to contain additional data types in the future.
Something like:
const array= ['string', {...}, {...}, 'string', 'string', {...}];
for (let i = 0; i < array.length ; i++) {
const str = array[i]
if( typeof str === 'string'){
/* perform logic on str */
}
See the typeof operator.
eg.
if (typeof array[i] !== 'string') {
continue;
}

A function within a reducer is affecting the wrong state property. I know why but I don't know what to do about it

I'm using a shuffle function in one of my reducers that takes as an argument an array of words from an object within the state. This function then creates a shuffledWords property within the object while keeping the original words array within the object.
The problem I'm getting is that when I put in the original words array into the function the function changes the original words array as well as creating the shuffled words array.
//REDUCER CASE
case 'CREATE_SHUFFLED_WORDS':
return state.map((dictionary) => {
if (dictionary.id === action.id) {
return {
...dictionary,
shuffledWords: shuffle(dictionary.words)
};
} else {
return dictionary;
};
});
Example of what happens:
//Before
{
words:['cat', 'dog', 'pig']
shuffledWords: []
}
//AFTER
{
words:['dog', 'pig', 'cat']
shuffledWords: ['dog', 'pig', 'cat']
}
//SHUFFLE FUNCTION
export const shuffle = (a) => {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
the problem is in your shuffle(dictionary.words). As I can not see the shuffle() method, I am suggesting a solution without modifying the shuffle method,
you can call the shuffle method like this,
shuffledWords: shuffle([...dictionary.words])

ReactJs - TypeError: Cannot assign to read only property 'name' of object '#<Object>'

I have an array of objects:
var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}]
All I want to do is to find the index of the object to change a name or a tag. I use this function:
function setSubcat(val, index, lang){
var newArr = []
var obj = {
'name': val
}
subcategories.map((val, i)=>{
if(index === i){
var newObj = Object.assign(val, obj)
newArr.push(newObj)
}
newArr.push(val)
})
setSubcategories(newArr)
}
The error happens at var newObj = Object.assign(val, obj)
I thought the error means I can't mutate the state directly and so I have to make a copy. I thought that mapping through subcategories and push it into a local newArr means I made a copy of the array. But it wasn't working when I wanted to change a value of object in it so I used Object.assign which I thought would deep copy the particular object from the array, but it's not working either.
What am I missing here?
As pointed in comments:
the code you posted does not show how you created object with unmodifiable property
you can create a new object and not use Object.assign to get rid of the error
use map function in more idiomatic way
interface TaggedItem {
name: string,
tag: string
}
var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}];
function setSubcat(val: string, index: number, _lang: any){
var obj: Partial<TaggedItem> = {
'name': val
}
var newArr: TaggedItem[] = subcategories.map((val, i)=>{
if(index === i){
return {
...val,
...obj
}
} else {
return {...val};
// or return val; if you don't need a full copy
}
})
console.log(newArr);
}
setSubcat('newName', 0, undefined);
Playground link

Push function appears to be overwriting each array element in Angular

I'm trying to push some conversation messages to an array using the below code:
myConversations: IConversation[] = [];
myConversationMessage: IConversationMessages = {
conversationId: 0,
messageId: 0,
messageText: ''
};
myConversationMessages: IConversationMessages[] = [];
this.conversationService.getConversations().subscribe(conversations => {
this.myConversations = conversations;
for (let i of this.myConversations) {
this.myConversationMessage.conversationId = i.conversationId;
for (let j of i.messages) {
this.myConversationMessage.messageId = j.messageId;
this.myConversationMessage.messageText = j.messageText;
this.myConversationMessages.push(this.myConversationMessage);
}
}
console.log(this.myConversationMessages);
});
I'm retrieving the Conversations & the Messages within them from a JSON object.
Instead of pushing each message to the myConversationMessages array, the following is being outputted in the console:
0
conversationId: 2
messageId:2
messageText: "testing"
1
conversationId: 2
messageId:2
messageText: "testing"
2
conversationId: 2
messageId:2
messageText: "testing"
3
conversationId: 2
messageId:2
messageText: "testing"
So the final "conversation" object is overwriting each array element.
Can someone please tell me why my code is doing this? Thanks a lot in advance
P.S. I can upload further code if it will clear up my issue.
It's because JavaScript objects are passed by reference:
myConversationMessages: IConversationMessages[] = [];
this.conversationService.getConversations().subscribe(conversations => {
this.myConversations = conversations;
for (let i of this.myConversations) {
this.myConversationMessage.conversationId = i.conversationId;
for (let j of i.messages) {
this.myConversationMessage.messageId = j.messageId;
this.myConversationMessage.messageText = j.messageText;
this.myConversationMessages.push(this.myConversationMessage); // <-= Here you are pushing a reference to the same object in every loop. In every loop you are updating the single object, and the reference in each array spot points to the same object
}
}
console.log(this.myConversationMessages);
});
Try this:
for (let i of this.myConversations) {
for (let j of i.messages) {
this.myConversationMessages.push({
conversationId: i.conversationId,
messageId: j.messageId,
messageText: j.messageText
});
}
}
That will make a new object for each iteration
It happened because you added reference object to array. In your example you did not add 3 objects to array, you added three reference of one object three times. And change of properties in one of them causes change in all others.
It should be works:
for (let i of this.myConversations) {
this.myConversationMessage.conversationId = i.conversationId;
for (let j of i.messages) {
let item = new IConversationMessages();
item.messageId = j.messageId;
item.messageText = j.messageText;
this.myConversationMessages.push(item);
}
}

TypeScript not able to iterate associative array

I have a service which populates my associative array in typescript,
fun populateData(){
let tempArr;
tempArr = [];
this.service.get('Post', 1, 'true').subscribe(
(response) => {
this.loadingIcon = false;
for (let i = 0; i < response.results.length; i++) {
tempList = response.results[i]['tags'];
for ( let iter of tempList){
if ( iter in tempArr) {
tempArr[iter] = tempArr[iter] + 1;
}else {
tempArr[iter] = 1;
}
}
}
},
(error) => {
if (error['status'] === 401) {
localStorage.clear();
this.router.navigateByUrl('/login');
} else {
this.router.navigateByUrl('/error');
}
}
);
console.log(tempArr);
/*
This function is inside a class, once I iterate get access to tempArr I will be assigning the tempArr data to a class variable like
for (items in tempArr){
this.data.push(items, tempArr[items]);
}
*/
}
I'm able to populate my associative array with the service above which gives the following output in console,
I'm not able to iterate through this array, I tried a couple of methods like the following,
for ( const key in tempArr) {
console.log(key + ':' + tempArr[key]);
}
I want both they key and values from the array.
TypeScript generally assumes that the keys to arrays are numbers. What you were doing might work but it's not very idiomatic. I'm not going to rewrite your whole function but here are a few pointers:
When constructing your associative array (map for short from now on) you should try using an object instead of an array:
const tagCounts: { [key: string]: number } = {};
for (const result of response.results) {
for (const tag of result.tags) {
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
}
}
Then you can iterate the result with:
for (const tag of Object.keys(tagCounts)) {
const count = tagCounts[tag];
// Other stuff here
}
Or if you have polyfills for Object.entries then with:
for (const [tag, count] of Object.entries(tagCounts)) {
// Other stuff here
}
Looking at your code, this.data.push also seems wrong: it will add a string and a number to your data array which is almost certainly not what you want. You might want to consider converting data to an object as well if you want to store key-value pairs.

Resources