How to keep track of the id number in an object when you iterate and add another object to it - javascript

I want to add another object to my exiting object but i doesn't get the value as others object have instead it gets a text, I tried a easy solution but didn't work, here is that i'm facing:
ConsoleLog Image
So instead of the key long I want to keep the numbers as they started from 0, but I don't know how?
Here is what I've tried:
const addToWatchlist = (movie) => {
const long = movies.length;
const data = {...movies, long: movie};
setMovies(movies)
ps: I'm using React.

const addToWatchlist = (movie) => {
movies.push(movie)
setMovies(movies)

Related

Assign values from one set of key/value pairs to keys of another?

I'm working with the outputs of an Intranet I don't control.
I have this string:
let template = 'LAWYER=|FIRM=|SUIT_DESCRIPTION=|DEF_COMMENT=|PLF_COMMENT=|';
It goes on longer, but that's the pattern.
Now there's another similar string, but with data assigned, as in this example:
let current= 'FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|PLF_COMMENT=some freeform text|LAWYER=Bob Smith';
Now, notice that not every element in template is necessarily represented in current, and the order may be different (if the latter fact is a big deal, I can ensure the order is the same).
What I'm trying to do, is take every element that is in current, and populate the matching element in template, if it exists. (or, alternatively and potentially preferred, insert every non-matching element in template into current, but ideally in the same order as template).
Using the date above, the result I'm looking for is:
result = 'LAWYER=Bob Smith|FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|DEF_COMMENT=|PLF_COMMENT=some freeform text|';
I'm not very accomplished with JavaScript :(
I tried various things in JSFiddle using split() and match() but I just made a mess of it.
// Convert the template to an array of keys
const getKeys = str => str.split('|').map(entry => entry.split('=')[0]);
// Convert the data to an object
const toObj = str => Object.fromEntries(str.split('|').map(entry => entry.split('=')));
// Reconcile the data with the template
const compile = (templateStr, dataStr) => {
const keys = getKeys(templateStr);
const data = toObj(dataStr);
return keys.reduce((results, key) => {
if(key) results.push([key, data[key] ?? '']);
return results;
}, []);
};
// Convert the results back into a string
const toString = data => data.map(entry => entry.join('=')).join('|') + '|';
// And then a test
let template = 'LAWYER=|FIRM=|SUIT_DESCRIPTION=|DEF_COMMENT=|PLF_COMMENT=|';
let current = 'FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|PLF_COMMENT=some freeform text|LAWYER=Bob Smith';
console.log(toString(compile(template, current)));

How to use a loop to create an object with keys from a list in typescript without using `Partial`?

Overview
Im trying to create an initialise an object with known keys, however the initial empty object {} that I need breaks my typing.
The problem:
I have a list of value, that I want to use as keys, and I want to initialise an object with those keys. In python i would do something like:
myDict = {key: value for (key, value) in zip(myKeys, [[]]*len(myKeys))}
This should give the myDict the type Record<myKeys, string[]>
In TS, i dont seem to be able to have the same luck, as i need to initialise the object to an empty list before i can populate it with my keys/values. I would rather not need to call it a partial, then coerce it into the correct type.
what ive tried:
I have tried:
const allPlanFeatures: Partial<Record<ExtensivePlanHandle, string[]>> = {};
for (const planId of extensivePlanList) {
const features = getFeaturesForPlan(planHandleToMonthly[planId], is4kEnabled, exportFlow);
allPlanFeatures[planId] = features;
}
return allPlanFeatures as Record<ExtensivePlanHandle, string[]>;
and
const allPlanFeatures: Partial<Record<ExtensivePlanHandle, string[]>> =
extensivePlanList.reduce(
(a, planHandle) => ({
...a,
[planHandle]: getFeaturesForPlan(
planHandleToMonthly[planHandle],
is4kEnabled,
exportFlow
),
}),
{}
);
return allPlanFeatures as Record<ExtensivePlanHandle, string[]>;
These do end up with the desired effect at the end of the day, but I'd rather be able to not have this partially working middle
You can try this:
const allPlanFeatures: Record<ExtensivePlanHandle, string[]> = {} as Record<ExtensivePlanHandle, string[]>;
this is not perfect, but sometimes you need to tell typescript compiler what is right.

Multiple Firebase listeners in useEffect and pushing new event into state

I want to retrieve a list of products in relation to the user's position, for this I use Geofirestore and update my Flatlist
When I have my first 10 closest collections, I loop to have each of the sub-collections.
I manage to update my state well, but every time my collection is modified somewhere else, instead of updating my list, it duplicates me the object that has been modified and adds it (updated) at the end of my list and keep the old object in that list too.
For example:
const listListeningEvents = {
A: {Albert, Ducon}
B: {Mickael}
}
Another user modified 'A' and delete 'Ducon', I will get:
const listListeningEvents = {
A: {Albert, Ducon},
B: {Mickael},
A: {Albert}
}
And not:
const listListeningEvents = {
A: {Albert},
B: {Mickael},
}
That's my useEffect:
useEffect(() => {
let geoSubscriber;
let productsSubscriber;
// 1. getting user's location
getUserLocation()
// 2. then calling geoSubscriber to get the 10 nearest collections
.then((location) => geoSubscriber(location.coords))
.catch((e) => {
throw new Error(e.message);
});
//Here
geoSubscriber = async (coords) => {
let nearbyGeocollections = await geocollection
.limit(10)
.near({
center: new firestore.GeoPoint(coords.latitude, coords.longitude),
radius: 50,
})
.get();
// Empty array for loop
let nearbyUsers = [];
// 3. Getting Subcollections by looping onto the 10 collections queried by Geofirestore
productsSubscriber = await nearbyGeocollections.forEach((geo) => {
if (geo.id !== user.uid) {
firestore()
.collection("PRODUCTS")
.doc(geo.id)
.collection("USER_PRODUCTS")
.orderBy("createdDate", "desc")
.onSnapshot((product) => {
// 4. Pushing each result (and I guess the issue is here!)
nearbyUsers.push({
id: product.docs[0].id.toString(),
products: product.docs,
});
});
}
});
setLoading(false);
// 4. Setting my state which will be used within my Flatlist
setListOfProducts(nearbyUsers);
};
return () => {
if (geoSubscriber && productsSubscriber) {
geoSubscriber.remove();
productsSubscriber.remove();
}
};
}, []);
I've been struggling since ages to make this works properly and I'm going crazy.
So I'm dreaming about 2 things :
Be able to update my state without duplicating modified objects.
(Bonus) Find a way to get the 10 next nearest points when I scroll down onto my Flatlist.
In my opinion the problem is with type of nearbyUsers. It is initialized as Array =[] and when you push other object to it just add new item to at the end (array reference).
In this situation Array is not very convenient as to achieve the goal there is a need to check every existing item in the Array and find if you find one with proper id update it.
I think in this situation most convenient will be Map (Map reference). The Map indexes by the key so it is possible to just get particular value without searching it.
I will try to adjust it to presented code (not all lines, just changes):
Change type of object used to map where key is id and value is products:
let nearbyUsersMap = new Map();
Use set method instead of push to update products with particular key:
nearbyUsersMap.set(product.docs[0].id.toString(), product.docs);
Finally covert Map to Array to achieve the same object to use in further code (taken from here):
let nearbyUsers = Array.from(nearbyUsersMap, ([id, products]) => ({ id, products }));
setListOfProducts(nearbyUsers);
This should work, but I do not have any playground to test it. If you get any errors just try to resolve them. I am not very familiar with the geofirestore so I cannot help you more. For sure there are tones of other ways to achieve the goal, however this should work in the presented code and there are just few changes.

Issue when pushing numbers to an array in TypeScript

The issue I am having is displayed in the picture.
I am able to convert the strings into number type using map but when wishing to push to an array of numbers I am unable to. Also I am trying to maintain types but I believe this may be the issue but I am unable to make headway.Maybe I should create another variable and store the newly created number values into that array? Also when console logging I am just getting the single value as a number and not as an array.
openValues: string | number[];
I hope someone can please help...
getData() {
this.pricingService.getDailyPricing().subscribe((data) => {
this.dailyData = data;
const timeSeries = data['Time Series (Daily)'];
const dailyDates = Object.keys(timeSeries);
dailyDates.forEach((parentKey) => {
const parentValue = timeSeries[parentKey];
const childKeys = Object.keys(parentValue);
this.dailyDates = new Date(parentKey);
childKeys.forEach((childKey) => {
const keyName = childKey;
const keyValue = parentValue[childKey];
this.timeSeriesSeperationMethod(keyName, keyValue);
});
});
});
}```
The image attached contains the issue.
[![The Image of this issue able to convert to number but unable to push to an array of numbers][1]][1]
[1]: https://i.stack.imgur.com/pL1JA.gif

In protractor: How do I create a method that only sends keys I specify

I have a method called populateProvidedValuesForNewMandate that looks like this
exports.populateProvidedValuesForNewMandate = (team, assignee, disputeValue, lawField,
subjectOfDispute, party, fileReference, costUnit, clientUnit, sideEffect, comment) => {
const teamInput = element(by.css('div#team input'));
const assigneeInput = element(by.css('div#assignee input'));
const disputeValueInput = element(by.id('dispute_value'));
const lawFieldInput = element(by.css('div#law_field input'));
const subjectOfDisputeInput = element(by.id('subject_of_dispute'));
const partyInput = element(by.id('party'));
const fileReferenceInput = element(by.id('file_reference'));
const costUnitInput = element(by.css('div#cost_unit input'));
const clientUnitInput = element(by.id('client_unit'));
const sideEffectInput = element(by.css('div#side_effect input'));
const mandateComment = element(by.id('mandate_comment'));
// TODO: Figure out how to choose these dynamically as well
// relevantCase, risReportRelevant, economicRelevance, activePassive
const relevantCaseInput = element(by.css(".relevant_case input[value='no']"));
const riskReportRelevantInput = element(by.css(".risk_report_relevant input[value='no']"));
const economicRelevanceInput = element(by.css("label[for='economic_relevance']"));
const activePassiveInput = element(by.css(".active_passive input[value='passive']"));
teamInput.sendKeys(team);
assigneeInput.sendKeys(assignee);
disputeValueInput.sendKeys(disputeValue);
lawFieldInput.sendKeys(lawField);
subjectOfDisputeInput.sendKeys(subjectOfDispute);
partyInput.sendKeys(party);
fileReferenceInput.sendKeys(fileReference);
costUnitInput.sendKeys(costUnit);
clientUnitInput.sendKeys(clientUnit);
sideEffectInput.sendKeys(sideEffect);
mandateComment.sendKeys(comment);
// TODO: Figure out how to choose these dynamically as well
// relevantCase, risReportRelevant, economicRelevance, activePassive
browser.actions().mouseMove(relevantCaseInput).doubleClick().perform();
browser.actions().mouseMove(riskReportRelevantInput).click().perform();
browser.actions().mouseMove(economicRelevanceInput).click().perform();
browser.actions().mouseMove(activePassiveInput).click().perform();
};
and here is an example of its use case
values.populateProvidedValuesForNewMandate(texts.DISPUTE_VALUE, texts.PARTY, texts.CLIENT_UNIT,
texts.SIDE_EFFECT, texts.COMMENT);
The method fills out the specified values that lie within a file called texts.js into the appropriate fields. The problem is that I get the error message: 'each key must be a number of string; got undefined' meaning that this method doesn't work because I have to send the keys for each specified variable in the method.
I really want to avoid sending empty strings for this method (especially because it won't work, I've tried it out -> I get a error from the app itself, not protractor/selenium).
How can I turn this method into one that only considers the specified variables in the test cases.
Also as you can see from my comment, I am trying to figure out how to do this for the checkbox and radio buttons as well. If anyone has a hint, I'd really appreciate it
Honestly, only you can answer the question. Because there are hundreds of ways to fo this, and some may work better than another. So to us it's silly to make guesses which way is the best for you. So I'll give one example and hopefully you can take it from here
One way is to make the method accept an object and check if a property has been passed
function fillForm(obj) {
if (obj.hasOwnProperty('team')) teamInput.sendKeys(team);
if (obj.hasOwnProperty('assignee')) assigneeInput.sendKeys(assignee);
if (obj.hasOwnProperty('disputeValue')) disputeValueInput.sendKeys(disputeValue);
// ...
}
and then call it
fillForm({
assignee: texts.ASIGNEE,
disputeValue: texts.DISPUTE_VALUE
})
so it will skip sending keys to team field

Categories