UPDATED SOLUTION: Adding Separate Ratings and Reviews to Individual Dynamic Pages and Dynamic List Page Repeater Items

PLEASE READ THE ABOVE POST TITLED “SOLUTION: Adding Separate Ratings and Reviews to Individual Dynamic Pages” FIRST FOR THE INTITIAL STEPS.
THIS POST IS JUST UPDATES TO THAT POST, WITH FIXES TO THE ISSUES I ENCOUNTERED.
I think I finally fixed all of them. I have tested out the pages and the ratings and comments system many times and it all seems to be working.
I am complete beginner, so please excuse any mistakes, if you find any :slightly_smiling_face:.

This is the url for the dynamic list page on our website:

https://www.collaborativediscussionproject.com/activities/module-1

This is the url for the dynamic item page on our website:

https://www.collaborativediscussionproject.com/items-1/1.1-what-is-collaborative-learning%3F

After I created the initial solution (mentioned in the SOLUTION post I linked above), when I was testing it again, my ratings display (yellow stars) were just going blank.

To fix this, I first did two things:

  1. Increased the time given to run the code - so wherever it says “setTimeout(function)”, at the end there is a number in the thousands. It used to be 5000 or 1500, I increased these numbers to 9000 and 20000. This does make it so it takes a little time for the number of comments to calculate, but I don’t think it is too noticable and it was the only thing that I could figure out to fix the problem.
  2. Made the entering a rating required - because if a comment is submitted without a rating being entered, with the code I used from the Velo tutorial to calculate the average rating, it doesn’t know what to do when no rating is entered. So, I made the rating required, by adding code to disable the submit button and only enable it once a rating is selected.
    In the final code below, I added this snippet/part in the onReady function to disable the button initially when the page is loaded and no rating has been selected:

// get the new rating from the ratings input
const newRating = $w(‘#commentsRatingsInput’).value;
if (newRating > 0) {
$w(‘#addCommentButton’).enable()
}
else {
$w(‘#addCommentButton’).disable()
$w(‘#commentsRatingsInput’).required = true;
}

I also added the following snippet to enable the Submit button once a rating is selected:

export function commentsRatingsInput_change(event) {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
const newRating = $w(‘#commentsRatingsInput’).value;
if (newRating > 0) {
$w(‘#addCommentButton’).enable()
}
else {
$w(‘#addCommentButton’).disable()
$w(‘#commentsRatingsInput’).required = true;
}
}

IMPORTANT: I also changed the Permissions of my CommentRatings collection so that is says Anyone can update content , since in this collection - each item/page has one line where the values in the avg, numRatings, and totalRatings keep updating everytime someone enters a rating. So, unlike other collections (like the Comments collection) where everytime someone enters a comment a new line is added, since this CommentRatings collection just updates the same line, you need to give permission to Anyone to update content, not just to view or add content:

Another issue I was having was that after a rating is selected, a name and comment entered and submitted, the ratings stars would still show the value that was selected and the name and comment box would be outlined it red - so I needed add code to reset the ratings star value to null and the reset the validity of the name and comment input boxes.
This is code I added in the .then part in my code:

$w(‘#commentsRatingsInput’).value = null
$w(‘#commentsInput’).resetValidityIndication()
$w(‘#nameInput’).resetValidityIndication()

THIS IS THE COMPLETE FINAL CODE ADDED TO THE DYNAMIC ITEM PAGE (i.e. the page with the Ratings input element and Name and Comments input boxes):

// Velo API Reference: Introduction - Velo API Reference - Wix.com

import wixData from ‘wix-data’;

$w.onReady(function () {
// TODO: write your page related code here…
//loadrating ()
// get the new rating from the ratings input
const newRating = $w(‘#commentsRatingsInput’).value;
if (newRating > 0) {
$w(‘#addCommentButton’).enable()
}
else {
$w(‘#addCommentButton’).disable()
$w(‘#commentsRatingsInput’).required = true;
}
setTimeout(function() {
let totalCount = $w(“#dataset1”).getTotalCount();
$w(‘#commentsCountBox’).text = totalCount.toString() + " comment(s)"
}, 9000);
});

export function commentsRatingsInput_change(event) {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
const newRating = $w(‘#commentsRatingsInput’).value;
if (newRating > 0) {
$w(‘#addCommentButton’).enable()
}
else {
$w(‘#addCommentButton’).disable()
$w(‘#commentsRatingsInput’).required = true;
}
}

export function addCommentButton_click(event) {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
//$w(‘#loader’).show()

// get the new rating from the ratings input
const newRating = $w(‘#commentsRatingsInput’).value;

$w(“#commentRatingsdataset”).onReady(() => {
// get the current item from the dataset
const currentItem = $w(“#commentRatingsdataset”).getCurrentItem();

// get the current average rating, number of ratings, and
//total ratings for the current dataset item
const average = currentItem.avg;
const count = currentItem.numRatings;
const total = currentItem.totalRatings;

// calculate the new average rating based on the current
//average and count
const newAverageLong = (total + newRating) / (count +1);
// Round the average rating to 1 decimal point
const newAverageShort = Number.parseFloat(newAverageLong).toFixed(1);

// set the dataset fields to the new average, total
// ratings, and number of ratings
$w(‘#commentRatingsdataset’).setFieldValues({
‘avg’: newAverageShort,
‘totalRatings’: total + newRating,
‘numRatings’: (count + 1)
});

// save the dataset fields to the collection
$w(‘#commentRatingsdataset’).save()
.catch((err) => {
console.log(‘could not save new rating’);
});
});

$w(‘#addCommentButton’).disable()
let page = $w(“#dynamicDataset”).getCurrentItem();
let pageId = page._id;
wixData.insert(‘comments’,{
‘comment’: $w(‘#commentsInput’).value.replace(‘Nigga’, ‘’).replace(‘nigga’,
‘’).replace(‘Nigger’, ‘’).replace(‘nigger’, ‘’).replace(‘Fuck’,
‘’).replace(‘fuck’, ‘’),
‘userName’ : $w(‘#nameInput’).value,
‘rating’ : $w(‘#commentsRatingsInput’).value,
‘pageId’ : pageId,
‘pageReference’ : pageId,
})
.then( () => {
$w(‘#commentsInput’).value = ‘’
$w(‘#nameInput’).value = ‘’
$w(‘#commentsRatingsInput’).value = null
$w(‘#commentsInput’).resetValidityIndication()
$w(‘#nameInput’).resetValidityIndication()
$w(‘#dataset1’).refresh()
setTimeout(function() {
$w(‘#addCommentButton’).enable()
//$w(‘#loader’).hide()
let totalCount = $w(“#dataset1”).getTotalCount();
$w(‘#commentsCountBox’).text = totalCount.toString() + " comment(s)"
}, 20000);
})
//wixData.insert(‘CommentRatings’, {
//‘pageId’ : pageId,
// ‘pageReference’ : pageId,
//})

}

function filterComments () {
let page = $w(“#dynamicDataset”).getCurrentItem();
let pageId = page._id;
$w(‘#dataset1’).setFilter(
wixData.filter()
.contains(“pageId”, pageId)
).then(() => {
setTimeout (function() {

    }, 20000); 
}); 
} 

export function dataset1_ready() {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
filterComments()
}

function filterCommentRatings () {
let page = $w(“#dynamicDataset”).getCurrentItem();
let pageId = page._id;
$w(‘#commentRatingsdataset’).setFilter(
wixData.filter()
.contains(“pageId”, pageId)
).then(() => {
setTimeout (function() {

    }, 20000); 
}); 
} 

export function commentRatingsdataset_ready() {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
filterCommentRatings ()
}

/**

  • Adds an event handler that runs when an input element’s value
    is changed.
    Read more
  • @param {$w.Event} event
    */

TO ADD THE AVERAGE RATINGS DISPLAY TO THE DYNAMIC LIST PAGE’S REPEATER ITEMS:

First, I went into my CommentRatings collection that is used to store, calculate and display the average rating and number of ratings for each dynamic item page (in my case, each activity’s page), and clicked on More Actions, then Export to CSV and exported all the fields and data into a .CSV file.

I then opened it using Excel and saved it as an excel file.
I then deleted all the other fields and data (i.e. columns in excel) except the pageId and Page Reference fields.
I then sorted the whole excel sheet by going to the top menu in Excel, then Data > Sort. I clicked my table has headers and sorted by the Page Reference field, A to Z, so all the data was in order of my pages since they all start with a number (i.e 1.1, 1.2 etc.).

I then went to my dynamic list page:
URL:
https://www.collaborativediscussionproject.com/activities/module-1

On the dynamic list page, in the collection for this page, in my case called Activities, I added a reference field that references the CommentRatings collection that is used to store, calculate and display the average rating and number of ratings for each dynamic item page (in my case, each activity’s page):

I then copied and pasted the page IDs from the PageId field next to the matching item page in the my Activities collection:

So, I’m not totally sure about this, because I can’t completely remember how I did it - but I think if you have the data i.e. page title and IDs in the excel file in the same order as the pages in the collection storing your item pages, you can copy and paste more than one line/cell at a time of Page IDs from the pageId column in the excel file into the Ratings Reference field in the items collection - in my case, the Activities collection.
If this doesn’t work, then you have to copy and paste in the page ID for each page one at a time.
HOWEVER YOU COPY AND PASTE, MAKE SURE TO DOUBLE CHECK EVERY SINGLE ONE OF YOUR PAGE IDS TO MAKE SURE IT MATCHES THE CORRECT PAGE - I obsessively did this like two or three times, lol! :rofl:

IMPORTANT NOTE: EVERY TIME YOU ADD A NEW ITEM TO YOUR DYNAMIC PAGES COLLECTION, YOU NEED TO ADD A NEW LINE AND SELECT THE PAGE IN THE PAGE REFERENCE FIELD AND ADD THE PAGE ID IN THE pageId FIELD IN THE COLLECTION STORING YOUR AVERAGE RATING AND NUMBER OF RATINGS (in my case the CommentRatings collection) AND THEN ADD THE PAGEID FROM THIS COLLECTION IN THE Ratings Reference field IN THE DYNAMIC PAGES COLLECTION (in my case, the Activities collection)!

Then you need to add a ratings display element to the repeater item on your dynamic page:

Because my repeater items are small, there is not enough space to show the number of ratings on the side, so I toggled this off in the Settings for the Ratings display element:

I then connected the Ratings display element to the Activities dataset and chose Ratings Reference: avg under Rating value connects to:

This will pull in the value from the “avg” field (1st column/field) in my CommentRatings collection and use that to show the average rating for each page/item in the Ratings display (i.e 5.0 right now in my case):

I then added two text boxes underneath and grouped them together - one text box (on the right) says “rating(s)”. The other text box on the left, I connected to the Activities dataset and chose Ratings Reference: numRatings under Text connects to:

This will pull in the value from the “numRatings” field (2nd column/field) in my CommentRatings collection and use that to show the number of ratings for each page/item in the Ratings display (i.e mostly 1 or 2 right now in my case):

IMPORTANT NOTE: EVERY TIME YOU ADD A NEW ITEM TO YOUR DYNAMIC PAGES COLLECTION, YOU NEED TO ADD A NEW LINE AND SELECT THE PAGE IN THE PAGE REFERENCE FIELD AND ADD THE PAGE ID IN THE pageId FIELD IN THE COLLECTION STORING YOUR AVERAGE RATING AND NUMBER OF RATINGS (in my case the CommentRatings collection) AND THEN ADD THE PAGEID FROM THIS COLLECTION IN THE Ratings Reference field IN THE DYNAMIC PAGES COLLECTION (in my case, the Activities collection)!

I think this covers everything I did - I hope it does, hehe :sweat_smile:…- It has been a while, because I was buried under everything I had to do for the relaunch of our website in December and wanted to wait till other people started entering ratings and reviews, to make sure everything was working, before I posted the fixes to the issues I found in this forum. If you have any questions, please leave them in the comments and I will try to answer if I know the answer - again, I’m just a beginner, so I might not.

Hope this helps!!!

Have fun!

1 Like

Letting just anyone update content might be troublesome as any one user can now go and edit everyone’s ratings.

Some other ways to approach this:

  • Have this Data Collection admin only and expose a JSW endpoint that does the updating of ratings in the collection.

  • Have a Data Collection with Site Member permissions to add/read data and Site Member Author permissions to update it. Then do a wixData.query().count() on the data collection to get rating counts. Indexes can also help here with making counts faster. Or you can have a scheduled job that does the counts every day and updates the ratings.

Just some ideas but I would really recommend against letting anyone change these ratings however they want to.

Hi Anthony,

Thank you so much for the suggestions.

As a beginner, I didn’t completely understand the methods you mentioned - it might be a bit advanced for me - like I don’t even know what JSW endpoint means, hehe :sweat_smile:. Maybe other people who know more than me will understand what you are saying, so thank you for taking the time to add your comments.

Still, I think it doesn’t apply to what I did - I might be wrong.
And sorry if I was not clear in my post…I think I mentioned this in my first post - https://www.wix.com/velo/forum/coding-with-velo/solution-adding-separate-ratings-and-reviews-to-individual-dynamic-pages

I have two separate collections I am using - one to display individual ratings and comments at the bottom of my page and another to calculate and dispaly the average rating and number of ratings at the top of the page.
The individual ratings that each user enters is stored in a separate/different collection called Comments that does not let anyone update the content, only admin can. It only lets anyone view and add content and you can see a new line is added for each rating and comment - so there are multiple lines for each item page (i.e. see multiple lines with the same page reference - for example, 2 lines for activity page 1.5):

The collection - CommentRatings - that I set the permissions to let anyone update is only used to calculate the number of ratings and the average rating for each item page (i.e so one row for activity page 5.8, one for 5.7, one for 5.6 etc, all the way to activity page 1.1) - so the collection has one line/row per page and the values in the avg, numRatings, and totalRatings field are updated/recalculated everytime for each line/row.

The problem I was having was that when a new rating is entered, the average and number of ratings values are updated based on the calculation run by the code and displayed in the ratings display element at the top. However, if I left the page and came back, the average rating and number of ratings values would go back to the original value.
It was a Wix support team member that told me to change the permissions to let anyone update content, and this is what fixed the issue.
The reason it kept going back to the original value everytime I navigated out the page I think is because without the permission for anyone to update content, it doesn’t store the updated values permanently in the collection.

To give an example of how the two collections I use work - when a user enters a new rating on say the page for activity 1.5 - this is what happens:

The rating they entered is stored as a new row in the separate collection I mentioned that does not let anyone update, but only add new content. You can see the screenshots for this in my first post https://www.wix.com/velo/forum/coding-with-velo/solution-adding-separate-ratings-and-reviews-to-individual-dynamic-pages

Then, say the starting values in the CommentRatings collection, in the row for page 1.5 is avg = 5, numRatings = 1, and totalRatings = 5, when a user enters a new rating of say 3, that value is not entered into this collection as a new row, but rather is used to calculate new values for that page’s existing line/row - so the values are updated to avg = 4, numRatings = 2, and totalRatings = 8.

Like this screenshot:

I hope this helps clarify what I did for anyone reading :slightly_smiling_face:.