https://www.wix.com/velo/forum/coding-with-velo/solution-adding-separate-ratings-and-reviews-to-individual-dynamic-pages
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 🙂.
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 http://wix.to/UcBnC-4
// 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: https://www.wix.com/velo/reference/api-overview/introduction
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 http://wix.to/UcBnC-4
// 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 http://wix.to/UcBnC-4
// 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 http://wix.to/UcBnC-4
// 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 http://wix.to/UcBnC-4
// Add your code for this event here:
filterCommentRatings ()
}
/**
* Adds an event handler that runs when an input element's value
is changed.
[Read more](https://www.wix.com/corvid/reference/$w.ValueMixin.html#onChange)
* @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! 🤣
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 😅...- 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!
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.