Populate a table within a repeater for a conference agenda tool

Hi,

I’m trying to build an agenda tool for a conference where users can save their favourite sessions using velo. Unfortunately, I could’t manage to populate a table within a repeater. It is needed to show the speakers of the different sessions, please cf. (and please ignore the ugly colors ;)):

The speakers are part of each session in the collection via a multiference field which is linked to the speaker collection. This is the code I have so far in this function that populates the repeater:

function populateList($item, wishlistItem) {
    // Get the wishlist session
    let session = wishlistItem.session;
 // is that a good way to get the speakers data?
  let speakers = wixData.query("Sessions_new")
        .eq("title", session)
        .include('speakers')
        .find();
// and now what?
 
  $item('#name').text = session.title;
  ... 
}

Can anyone give me – a js noob, obviously :wink: – a hint on how to approach this challenge? Thanks for your help!

Update: I now managed to populate the table with data using this code:


 wixData.queryReferenced("Sessions_new", session._id, "speakers")
        .then((myResults) => {
            if (myResults.items.length > 0) {
                let speakers = myResults.items;
                console.log(speakers);
                $item("#table1").rows = speakers;
            } else {
                console.log("No results found.");
            }
        })

But it’s not doing it reliably, I guess, it’s a timing problem? Any hint appreciated!

1 Like

Is this all the code? Is it inside your $w.onReady function?

1 Like

No, this is all relevant code (copy/pasted/adapted form a wishlist code). What I want to achieve is that a click of a button “My favs” re-populates the public session list and shows the user’s favourites. Thanks for taking a look!

// For full API documentation, including code examples, visit http://wix.to/94BuAAs

//-------------Imports-------------//

// Import the wix-data module for working with queries.
import wixData from 'wix-data';
// Import the wix-users module for working with users.
import wixUsers from 'wix-users';
// Import the wix-location module for navigating to pages.
import wixLocation from 'wix-location';

//-------------Global Variables-------------//

// Current user.
let user = wixUsers.currentUser;

//-------------Page Setup-------------//

$w.onReady(async function () {

    // Define how to set up each new repeater item

    checkWishlist();
    setupHandlers();
});

// Load and display the current user's wishlist.
async function loadWishlist() {
    // Hide the "notInWishList" image with a fade effect.
    $w('#notInWishList').hide('fade', { duration: 100 });
    // Show the "inWishList" image with a fade effect.
    $w('#inWishList').show('fade', { duration: 100 });
    // Get the current user.
    let user = wixUsers.currentUser;
    // Query the "products-wishlist" collection for all wishlist items belonging to the current user.
    let wishlistResult = await wixData.query("Session_User_Wishlist")
        .eq("title", user.id)
        .include('session')
        .find();

    // If any wishlist items were found:
    if (wishlistResult.length > 0) {
        // Expand the wishlist.
        $w("#wishlist").expand();
        // Collapse the empty wishlist.
        $w("#emptyWishlist").collapse();
        // Set the wishlist repeater's data.
        $w("#wishlist").data = wishlistResult.items;
        // Set the action that occurs when the wishlist repeater items are loaded to the myItemReady() function. 
        $w('#wishlist').onItemReady(myItemReady);
    }
    // If no wishlist items were found:
    else {
        // Collapse the wishlist.
        $w("#wishlist").collapse();
        // Expand the empty wishlist.
        $w("#emptyWishlist").expand();
    }
}

async function myItemReady($item, wishlistItem) {
    // Get the wishlist product.
    let session = wishlistItem.session;

    $item('#name').text = session.title;

    // $item("#buttoniD").link = "/sessions/"+session.title;
    $item('#buttoniD').onClick(() => {
        wixLocation.to(session["link-sessions-1-title"]);
    });
    $item('#removeItem2').onClick(removeItem(wishlistItem._id));

    let myResults = await wixData.queryReferenced("Sessions_new", session._id, "speakers");

    if (myResults.items.length > 0) {
        let speakers = myResults.items;
        console.log(speakers);
        $item("#table1").rows = speakers;
    } else {
        console.log("No results found.");
    }

}

//-------------Page Setup-------------//

function setupHandlers() {
    // Set the action that occurs when the login message is clicked to be the loginMessageClick() function.
    $w('#loginMessage').onClick(async () => {
        // Set the login options.
        let options = { "mode": "login" };
        // Hide the login message.
        $w('#loginMessage').hide();
        // Prompt the user to login using the options created above.
        await wixUsers.promptLogin(options);
    });

    // Set the action that occurs when the "notInWishList" image is clicked.
    $w('#notInWishList').onClick(() => {
        // If the current user is logged in:
        if (user.loggedIn)
            // Add the current product to the wishlist.
            // addToWishlist();
            loadWishlist();
        // If the current user is not logged in:
        else
            // Show the login message.
            $w('#wishlist').collapse();
        // Expand the empty whishlist.
        $w('#emptyWishlist').expand();
        $w('#loginMessage').show();
    });
}

It looks like the code is currently querying Sessions_new every time a new item is added to the repeater. I think you’ll be able to get it to populate properly if you replace the code below so that it does the query of Sessions_new specified in the myItemReady function.

Basically you want this query to run when initially loading the wishlist rather than every time an item is added with onItemReady.

    let wishlistResult = await wixData.query("Session_User_Wishlist")
        .eq("title", user.id)
        .include('session')
        .find();

    // If any wishlist items were found:
    if (wishlistResult.length > 0) {
        // Expand the wishlist.
        $w("#wishlist").expand();
        // Collapse the empty wishlist.
        $w("#emptyWishlist").collapse();
        // Set the wishlist repeater's data.
        $w("#wishlist").data = wishlistResult.items;
        // Set the action that occurs when the wishlist repeater items are loaded to the myItemReady() function. 
        $w('#wishlist').onItemReady(myItemReady);
    }
    // If no wishlist items were found:
    else {
        // Collapse the wishlist.
        $w("#wishlist").collapse();
        // Expand the empty wishlist.
        $w("#emptyWishlist").expand();
    }

So replacing the above code with something like:

    let myResults = await wixData.queryReferenced("Sessions_new", session._id, "speakers");

    if (myResults.items.length > 0) {
        let speakers = myResults.items;
        console.log(speakers);
        $item("#table1").rows = speakers;
        // Set the action that occurs when the wishlist repeater items are loaded to the myItemReady() function. 
        $w('#wishlist').onItemReady(myItemReady);
    } else {
        console.log("No results found.");
    }

And then removing the Sessions_new query logic and related code from the myItemReady function.

This is just an example to illustrate, not sure I have it perfect, but it should get you along the way.

1 Like

Thank you, but this solution would get only one set of speakers, right? What I’m trying to achieve is a list of conference sessions showing their assigned speakers each. Technically, this would be a table within a repeater which is connected to a multi reference field in the sessions collection. So the script should load the list of sessions that the user added to the wishlist, populate a repeater with the data and then look up the speakers for each session and populate the table within the repeater, like so:

This works well when I use these normal wix features:

image

But now I would love to do it with Velo, so that I can add a wishlist functionality. Can you help here? Thanks so much!

  1. First make sure, that the repeater accepts nested objects…

Ordinary object…

[
  {
    "_id": "1",
    "firstName": "John",
    "lastName": "Doe",
    "image": "http://someImageUrl/john.jpg"
  },
  {
    "_id": "2",
    "firstName": "Jane",
    "lastName": "Doe",
    "image": "http://someImageUrl/jane.jpg"
  }
]

Nested…

[
  {
    "_id": "1",
    "firstName": "John",
    "lastName": "Doe",
    "image": "http://someImageUrl/john.jpg",
    "nestedData": {"x": "x", "y": "yy", "z": ["aa", "bb", "cc", "dd", "ee"]}
  },
  {
    "_id": "2",
    "firstName": "Jane",
    "lastName": "Doe",
    "image": "http://someImageUrl/jane.jpg",
    "nestedData": {"z": "zz", "y": "yy", "z": ["ff", "gg", "hh", "jj", "kk"]}
  }
]

Test first, if repeater is able to handle such data-structure and do not crash when loading this kind of data-package. If REPEATER do accept nested OBJECTS —> then it will be possible to generate your wished function by code.

  1. Check if you are able to add a table into a repeater.

But normaly it is enough to know if the REPEATER is able to work with nested objects.

  1. You load the NESTED-DATA into your REPEATER …
    let repeaterData = $w("#myRepeater").data;

  2. Repater gets loaded onReady()…

$w("#myRepeater").onItemReady( ($item, itemData, index) => {
   console.log(itemData);
   console.log(itemData.nestedData);
  $item("#myRepeatedText").text = itemData.textField;
} );

Take a look into console to check for nested data.
Once you have confirmed that nested data is working → do what ever you want with it.

2 Likes

Thx, I have built a perfectly well working prototype that has a table inside using standard wix tools:

Now I want to reproduce this standard functionality in Velo - and this is where I’m stuck. Where would I put that query that fetches the table data within a repeater?

1 Like

This is how your setup should look like…

let myData = [
	{
		"_id": "1",
		title: 'My-Title-1',
		"firstName": "John",
		"lastName": "Doe",
		"age": 31,
		"image": "http://someImageUrl/john.jpg",
		"nestedTableData": [{"field1": "aaaaa", "field2": 'bbbbb', "field3": 45}]
	},
	{
		"_id": "2",
		title: 'My-Title-2',
		"firstName": "Jane",
		"lastName": "Doe",
		"age": 24,
		"image": "http://someImageUrl/jane.jpg",
		"nestedTableData": [{"field1": "Tom", "field2": 'Smirnof', "field3": 15}, {"field1": "Anna", "field2": 'Lincoln', "field3": 22}]
	}
];


$w.onReady(()=> {
	setTable();
	
	//--------------------------------
	$w("#repeater1").data = myData;
	//--------------------------------
	$w("#repeater1").onItemReady( ($item, itemData, index) => {
		console.log('Item-Data: ', itemData);
		console.log(itemData.nestedData);
		$item("#txtTitle").text = itemData.title;
		$item("#txtFirstname").text = itemData.firstName;
		$item("#txtLastname").text = itemData.lastName;
		$item("#table1").rows = itemData.nestedTableData;
	});
});


function setTable() {
	$w("#table1").columns = [
	{
		"id": "col1",
		"dataPath": "field1",
		"label": "Firstname",
		"width": 100,
		"visible": true,
		"type": "string",
		"linkPath": "link-field-or-property"
	},
	{
		"id": "col2",
		"dataPath": "field2",
		"label": "Lastname",
		"width": 100,
		"visible": true,
		"type": "string",
		"linkPath": "link-field-or-property"
	},
	{
		"id": "col3",
		"dataPath": "field3",
		"label": "Age",
		"width": 100,
		"visible": true,
		"type": "number",
		"linkPath": "link-field-or-property"
	}
	];
}

And here the example…
https://russian-dima.wixsite.com/my-site-13/nested-data

As we can see → REPEATER is able to read NESTED-DATA
And yes also it is possible to add a table into repeater.

So your wished functionality is possible to be generated.

All you have to do now —> is to replace the EXAMPLE-DATA → against your own one (fetched from an external site, or using wix-data-api to get it from your Wix-Databse, or connect your Wix-Database by a DATASET and code the DATASET by CODE.

GOOD LUCK & HAPPY CODING!!!

2 Likes

Thank you so much for your efforts! Unfortunately, I’m still stuck.

My situation is this:

I fetch the sessions a user has put on his wishlist from a collection in the cms that has a user_Id field and a reference field (which points to a conference session title in a different collection). Then I get something like this:

{
    "items": [
        {
            "_id": "eb9b60...",
            "session": {
        
                "_id": "02e1ff81...",
                "title": "This is the title of the 1st session in the Wishlist"
            },
            "member_id": "addssd"
        },
        {
            "_id": "eabss60...",
            "session": {
        
                "_id": "032ef81...",
                "title": "This is the title of the 2nd session in the Wishlist"
            },
            "member_id": "addssd"
        },
    ]
}

With these data I can populate the repeater. Now I need to get the speaker data for each session which again is a reference field in the session collection for which I uses this part:

let myResults = await wixData.queryReferenced("Sessions_new", session._id, "speakers");

The problem I have is that I don’t know where to put these repeated queries in the process of populating the repeater. In the end the speaker data need to go in the table within the repeater, see the image in this thread. Could you give me a hint?

1 Like

BEFORE you POPULATE your REPEATER with DATA, all your DATA has already to be prepared well. —> Your whole data must be prepared well, before pushing the data to REPEATER.

Your steps are somekind of strange (wrong).

  1. I fetch the session → geting some data.
  2. Already at this point populating the repeater.
  3. But then again using wix-data to get some referenced data, but already populated your repeater with data???

Right steps:

  1. Get first prepared all the repeater-data well.
  2. Push data to your repeater.

Just 2-steps needed.

So you are pushing the data into repeater, although your data for repeating is not complete at this moment. This is what i see.

And because your STEPS are wrong →

The problem I have is that I don’t know where to put these repeated queries in the process of populating the repeater. In the end the speaker data need to go in the table within the repeater, see the image in this thread. Could you give me a hint?

→ This is why you do not know where to put your last found data inside.

It is like —> the bus is already gone → but you still waiting for the bus.

Take a look again onto my example. → MY REPEATER-DATA —> is COMPLETELY PREPARED when i push it into my REPEATER, including already all needed data (NESTED-DATA for TABLE) to be shown inside REPEATER.

2 Likes

Thanks, now I see a ray of light at the end of the tunnel… :wink:

So if I understand you correctly, the main thing I should learn now is how to assemble a meaningful database from various queries in a loop… I will try my best, thanks again!

1 Like

Your steps are somekind of strange (wrong).

  1. I fetch the session → geting some data.
  2. Already at this point populating the repeater.
  3. But then again using wix-data to get some referenced data, but already populated your repeater with data???

Change your steps and i am sure, you will get your wished results.
All you need to be successful …

a) You have collected all your data
b) You have prepared the DATA into the right format → so the REPETER can read it.
c) You have populated the repeater.
d) Nested data is loaded into the table?
e) At least you have an already working simple example.

2 Likes

Solved it. Thank you so much for your help!

2 Likes