Wix Velo — How to work with Array of Object - javascript

I'm currently building a website on Wix, and have come across a problem I can't think myself out of. Neither Wix support or the Wix Velo Forum have been able to help me out.
I have a repeater that is connected to the Stores/Products collection, and in the Stores/Products collection there's a collection field that contains additional info sections on the product. I have three info section; Tempo, Genre and Tags. Each contains a description.
It looks like this:
[
{
"title": "Tempo",
"description": "<p>142 BPM</p>\n"
},
{
"title": "Genre",
"description": "<p>Jazz</p>\n"
},
{
"title": "Tags",
"description": "<p>Frank Ocean, Travis Scott</p>\n"
}
]
I have figured out how to pull the individual objects with this code:
export function audioRepeater_itemReady($item, itemData, index) {
let product = $item('#dataset3').getCurrentItem(itemData._id)
let ArrayAdditionalInfo = []
ArrayAdditionalInfo = product.additionalInfoSections
ArrayAdditionalInfo.forEach((element) => {
console.log(element.title)
console.log(element.description)
})
But I want it to be able to figure out if eg. the Title === "Genre", then it will show the description from that array, like this:
{
// if equal to this:
"title": "Genre",
// show me this
"description": "<p>Jazz</p>\n"
},
The whole plan with this is to show the description output in a text element that I can implement in the repeater.
I have tried with if statements, but I just can't put it together myself. If this is confusing I'll gladly elaborate.
Thank you in advance.

I'm not a 100% sure if I understood the question correctly, but if you want to show all titles, and, conditionally the description if the title is Genre, you could just use a Ternary:
let data = [{
"title": "Tempo",
"description": "142 BPM\n"
},{
"title": "Genre",
"description": "Jazz\n"
},{
"title": "Tags",
"description": "Frank Ocean, Travis Scott\n"
}];
data.forEach(e => $("#products").append(
`<p>Title: ${e.title}${
e.title === "Genre"
? "<br>description: " + e.description
: ""
}</p>`
));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="products">
</div>

I think your issue related to handler. You use repeaters onItemReady handler, which is not the best option for your case. It calls for each row in repeater. Instead of this I recommend to use dataset's onReady
$w("#dataset3").onReady( () => {
console.log("The dataset is ready");
$w("#audioRepeater").getItems(0, 20).then( (result) => {
let items = result.items;
items.forEach((element) => {
if (element.title === 'Genre') {
doWhatDoYouWant(element)
}
})
} ).catch( (err) => {
let errMsg = err.message;
let errCode = err.code;
} );
} );
Please take into consideration that this block should be inserted into $w.onReady

Related

Iterating over nested data JS

I'm a little bit new to programming and very new to JS so I apologize for the beginner question.
I'm trying to iterate through this data and get each tracks name and artist but I'm having an issue. Currently I'm trying something like this.
If anybody has any insight or suggestions I would appreciate it greatly.
I'm using a rails backend with JS frontend. Thank you!
function selectTracks(){
fetch(BACKEND_URL)
.then(response => response.json())
.then(playlist => {
playlist.data.forEach(playlist => {
`<h4> ${playlist.attributes.track.name}</h4>
<h4>${playlist.attributes.track.artist}></h4> `
// let newPlaylist = new Playlist(playlist, playlist.attributes)
console.log(fetch)
// document.getElementById("playlist-container").innerHTML += newPlaylist.renderPlaylistCard();
debugger
}
)}
)
}
My serializer looks like this
{
data: [
{
id: "1",
type: "playlist",
attributes: {
name: "Country Songs",
id: 1,
track_id: 10,
track: {
id: 10,
name: "First Song",
artist: "Randy",
created_at: "2020-06-17T02:09:07.152Z",
updated_at: "2020-06-17T02:09:07.152Z"
}
},
relationships: {
track: {
data: {
id: "10",
type: "track"
}
}
}
}
]
}
You need to replace forEach with map. The 'forEachloop doesn't return anything. But themapmethod return an array. (An array of HTML elements in your case
fetch(BACKEND_URL)
.then(response => response.json())
.then(playlist => {
return playlist.data.map(playlist => {
`<h4> ${playlist.attributes.track.name}</h4>
<h4>${playlist.attributes.track.artist}></h4> `
// let newPlaylist = new Playlist(playlist, playlist.attributes)
console.log(fetch)
// document.getElementById("playlist-container").innerHTML += newPlaylist.renderPlaylistCard();
debugger
}
)}
)
Your code technically works assuming that the BACKEND_URL is correct and the json is valid. But, in its current state, it doesn't do anything with the data. If you output the h4 tags, for instance, you should see them written to the screen.
document.write(
`<h4> ${playlist.attributes.track.name}</h4>
<h4>${playlist.attributes.track.artist}</h4> `
)
Or alternatively you could log the values out to prove that you are processing the data correctly:
console.log(playlist.attributes.track.name, playlist.attributes.track.artist)
If not, the next thing to check is the validity of your json. I'm assuming that you copied your json from the browser which will strip some quotes for readability. View the source to ensure that the key names are correctly wrapped in quotes like this:
{
"data": [
{
"id": "1",
"type": "playlist",
"attributes": {
"name": "Country Songs",
...
If you are using ActiveModel Serializers, they should be formatted correctly.
If your json is valid and you can write the h4 tags to the page with the correct data in them, then the problem probably lies in your Playlist class.
Another handy tool for diagnosing fetch() problems is in Chrome Developer Tools. Go to the Network and click the XHR filter. This will allow you to inspect the fetch request and see if the response is valid and the data is what you expect. Other browsers have a similar feature.

Adding a new object into a nested array

I want to add a new object for each nested array. I'm calling this function any time I add a product to my orderintake:
add2order(productID, productName, productRatePlans) {
this.orderIntake.push({ productID, productName, productRatePlans });
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
this is an example response from the server:
{
"id": "8adc8f996928b9a4016929c59b943a8f",
"sku": "SKU-00006778",
"Partner_Account_ID__c": null,
"productRatePlans": [
{
"id": "8adce4216928c28d016929c59bff3372",
"status": "Active",
"name": "Enterprise",
"description": null,
"effectiveStartDate": "2016-02-26",
"effectiveEndDate": "2029-02-26",
"productRatePlanCharges": [
{
"id": "8adc8f996928b9a4016929c59d183a92",
"name": "USAGE_COUNTER_2",
"type": "Usage",
"model": "Volume",
"uom": "Each",
"pricingSummary": [
"Up to 5000 Each: USD0 flat fee"
],
"pricing": [
{
...
}
],
"defaultQuantity": null,
"applyDiscountTo": null,
"discountLevel": null,
"discountClass": null,
...
"financeInformation": {
..,
}
}
]
}
],
"productFeatures": [
{
...
}
]
}
The data is being retrived this way from an external REST backend so unfortunately I can't initialize the data including the new property...
so in every productRatePlanCharges there should be 1 new object 'quantity'.
How can I add this field to every productRatePlanCharges?
Right now I'm getting: ERROR
TypeError: Cannot read property 'productRatePlanCharges' of undefined
And how can I make sure I'm always adding this to the last orderIntake element? Don't mind productRatePlans there is only 1 in each orderintake...
thanks for your support!
Here you have to create productDetails object with inititalised array like below so that you won't get the error.
add2order(productID, productName, productRatePlans) {
// Create object like below
let productDetails = { productID : productID, productName : productName, productRatePlans : productRatePlans
}
this.orderIntake.push(productDetails);
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
Hope this will help!
as you used Angular you probably use Typescript too. I recommend that you create a model like your incoming model and there define your quantity: number inside productRatePlanCharges object. then map the incoming data to your own model. therefore you will have a quantity=0 in your model that you can change it later in a loop.
If you want to continue with your own way take a look at this:
Add new attribute (element) to JSON object using JavaScript
there is no problem to add an element to current model almost like you did, and the problem might be somewhere else as your error refers to existence of productRatePlanCharges!
as you used forEach I prefer to use that 'element' and double iterating with i++; is not a good idea to me.
this might be better:
element.quantity = element.defaultQuantity;

Join With AngularFire 2

I have seen similar questions asked, but those questions had slightly different data structures to what I'm dealing with. I've looked at:
Joining data between paths based on id using AngularFire
AngularFire2: Perform 'Joins' on FirebaseListObservables using RxJS .map()
This is my data structure:
{
"samples": {
"24084": {
"addInfo": "TEST",
"datePrinted": "8/11/2017 9:42:57 AM",
"equipment": "GR028",
"hmisNumber": "100E",
"lotNumber": "GR0030C659-JM",
"productionNumber": "PN0034781",
"userName": "MCorbett"
},
"24342": {
"addInfo": "test",
"datePrinted": "8/15/2017 11:51:55 AM",
"equipment": "GR025",
"hmisNumber": "100",
"lotNumber": "BR0010P835",
"productionNumber": "PN0035616",
"userName": "MCorbett"
}
},
"scans": {
"-Krlb3tv3oFPtYZp2ErX": {
"inTime": 1502997139131,
"sampleId": "24342"
},
"-KrlbdbCT0us6xE9POm3": {
"inTime": 1502997289573,
"outTime": 1502997292524,
"sampleId": "24342"
},
"-Krlc3vsjiQ9czWYGvA9": {
"inTime": 1502997401784,
"outTime": 1502997404864,
"sampleId": "24084"
}
}
}
As you can see, Samples to Scans have a one to many relationship. What I need to do is populated a table with Sample data joined to scan data. It needs to look like this:
"24342": {
"addInfo": "test",
"datePrinted": "8/15/2017 11:51:55 AM",
"equipment": "GR025",
"hmisNumber": "100",
"lotNumber": "BR0010P835",
"productionNumber": "PN0035616",
"userName": "MCorbett",
"inTime": 1502996197213
}
I need to grab all Scans where outTime is undefined, and then join it to it's corresponding Sample data. Here is what I have tried so far:
// Get samples that have a scan where inTime is populated but outTime is not
getOpenSamples() {
console.log('getopensmaples stareted')
let scanWithSampleList = this.scanSvc.getScansList({
orderBy: 'outTime',
startAt: ''
})
.switchMap(scans => {
let sampleObservables = scans.map(scan => this.getSample(scan.sampleId));
console.log("insisde");
return sampleObservables.length === 0 ?
Observable.of(scans) :
Observable.combineLatest(sampleObservables, (samples) => {
scans.forEach((scan, index) => {
scan.productionNumber = samples[index].productionNumer;
scan.lotNumbner = samples[index].lotNumber;
});
return scans;
});
});
}
This gives me this error:
ERROR in C:/Users/corbetmw/workspace/angular/sample-time-tracking/src/app/samples/shared/sample.service.ts (82,54): Propert
y 'productionNumer' does not exist on type '{}'.
What am I doing wrong here? This seems like a simple enough thing, but I'm having a lot of trouble with it. Do I need to change my data structure? Should I make a component that gets the Scans with undefined outTime and stick it in the table with a parent that can pass the sample ID, or vice versa?
I was able to find a solution which returns an observable of type Scan<> with a single Scan inside of it.
I have this function:
getOpenScans() {
const scansList = this.db.list('/scans', ref => ref.orderByChild('outTime').endAt(null));
return scansList.snapshotChanges().map(arr => {
return arr.map(snap => Object.assign(snap.payload.val(), {
$key: snap.key
}))
})
}
Then, I have this guy:
getOpenSamples() {
let openScans = this.scanSvc.getOpenScans();
let fullSamples = openScans.map(scans => {
for (let scan of scans) {
scan.sample = this.getSample(scan.sampleId);
}
return scans;
});
//fullSamples.subscribe(samples => console.log(samples));
return fullSamples;
}
I am now trying to implement this solution with MatTable in Material2.

On/off toggle for filtering content React

This React code is filtering variables according to the "tag" which it contains (as seen in the list array).
However, I cannot toggle the filter variables (tags) on/off.
I want to be able to turn certain filters on/off, and have just those filters apply.
How is this achieved?
My entire code is in this codepen (
http://codepen.io/yarnball/pen/GqbyWr?editors=1010)
I believe I have to some how add it to the array on line 79 (below), but I have not had success with this
Line 79:
selectTag: function (tag) {
this.setState({
displayedCategories: this.state.displayedCategories.concat([tag]),
$push : [newObject]
});
},
My data looks like this:
"title": "Into the Wild",
"tag": [
{
"name": "Movie",
"taglevel": 1,
"id": 1
},
{
"name": "Adventure",
"taglevel": 2,
"id": 30
},
{
"name": "Book",
"taglevel": 1,
"id": 2
}
],
"info": []
}
In order to toggle the filters, you will need to check for the existence of the tag in the existing displayedCategories, look through the array for the tag, and then either remove it or add it in.
It is normally my preference to try to be functional so that assignment cannot cause confusion, so I will use a mostly functional style.
First to check for the presence of the tag we can use a filter operation.
var filteredCategories = this.state.displayedCategories
.filter(function (existingTag) {
return existingTag.taglevel !== tag.taglevel ||
existingTag.id !== tag.id;
});
So we now have a list of tags that are filtered to only include those that don't match the passed tag. We can check if the filtered list is the same size as the old list to see if we removed one. Alternatively, we could have filtered the other way around to see if we needed to remove one using some.
if (filteredCategories.length === this.state.displayedCategories.length){
// tag wasn't present, add it
} else {
// tag was present, use filtered list.
}
As I said above, I prefer functional, so we can do it slightly differently:
var newCategories = filteredCategories.length === this.state.displayedCategories.length ?
filteredCategories.concat([tag]) :
filteredCategories;
and then we need to set state:
this.setState({
displayedCategories: newCategories,
});
To combine those together:
var filteredCategories = this.state.displayedCategories
.filter(function (existingTag) {
return existingTag.taglevel !== tag.taglevel ||
existingTag.id !== tag.id;
});
var newCategories = filteredCategories.length === this.state.displayedCategories.length ?
filteredCategories.concat([tag]) :
filteredCategories;
this.setState({
displayedCategories: newCategories,
});

Get all documents with specific nested field value, sans one document

I have a table videos with documents that look like this:
{
"title":"Video Name",
"description": "A description",
"slug":"video-name",
"studio": {
"name": "Studio Name",
"uid":"zyxwvut"
},
"uid":"abcdefghijkl"
}
I'm trying to grab related videos by the current video's studio by getting all videos with the studio.uid of zyxwvut, while also removing the ID of the requested video (uid of abcdefghijkl).
I've tried a few queries:
r.db('dev').table('videos').filter(function(video){ return video('studio')('uid').contains('zyxwvut').and(r.not(video('uid').eq("abcdefghijkl"))) })
with r.js:
r.db('dev').table('videos').filter(function(video){ return r.('(function (video) { return video.studio.uid == "zyxwvut"; })').and(r.not(video('uid').eq("abcdefghijkl"))) })
Am I going about this all wrong, or is it not possible?
You were close. You can do:
r.db('dev').table('videos').filter(function(video) {
return video("studio")("uid").eq("zyxwvut")
})

Categories