function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Kenji775Kenji775 

Sub Selects

Hey everyone. I have another probably easy question. The Salesforce site I am building is totally powered by a custom object called Website_data__c. All the content for the site is held in records that are of that type. On the Website_data__c object, there is a field called sub_menu__c (it is a picklist). That list defines which menu this particular page will show up on. There are 4 possible options.

 

My Visual force page starts has the standard controller set to that object, and the recordsetvar set. Of course that pulls all records for that object.

 

Page TitlePage IdSub Menu
Home Pagea0Y4000000127tvEAAMain
Text Pagea0Y4000000127uUEAQMain
Careersa0Y4000000127ztEAAAbout FPI
Contact Usa0Y400000012803EAAAbout FPI
Driving Directionsa0Y40000001280DEAQTester Info

 

Thats what the results look like. However I need to divide that into 3 seperate lists (based on the sub menu attribute), or somehow filter out any links that don't belong to the sub menu I am interested in when creating my link list. So really I just want to run selects against the record set, or have a loop with an if statment or something. Being so totally new to visual force, I don't know how to include logic of any kind on my pages (or if it's even possible). Thanks ahead of time.

 

 

mtbclimbermtbclimber

I don't know the full scope here but if you need all the pages you are getting back now and don't need the set "filtered" in the sense your page will only present one submenu set then you have options. You can either manage the data on the client by using the expression bound back to the recordsetvar in script to loop over the collection and create the client side structure OR you can extend the standardsetcontroller with apex and do the grouping on the server

Kenji775Kenji775

Hmm, well I am going to originally need to full set of data, then I need to break that into sub sets. This is for building a navigation menu, so I need to pull all the pages available. Then based on their sub menu I put them into different sections. The filtering can happen on the client, or the server, doesn't matter to me. To me looping over the record set and creating lists based on some criteria inside the loop would make the most sense.

 

Psudeo Code

//Create a structure to hold all my links

Links = structnew();

 

//Loop over every record found in the website_data__c collection, call the item in each iteration pageData, have an index of i that should incriment by 1 each iteration.

For every record found in the website_data__c record set, item reference = pageData, index i

{
       //If a key by the name of sub_group does not exist in this structure create it

       if(not isdefined(Links[pageData.sub_group__c])

       {
            Links[pageData.sub_group__c] = arraynew(1);

       }

 

       //Key now we need to define that data contained in this element of the array is a structure as well

       Links.pageData[1] = structnew();

       

       //Store the data needed to create this link in the structure within this array

       Links[pageData.sub_][i].id= pageName.id

       Links[pageData.sub_][i].name= pageName.name

 

       i++;

}

 

With that I would end up with a data structure that would look like

Links.main[1].id = a0Y4000000127tvEAA;

Links.main[1].name = Home Page;

Links.main[2].id = a0Y4000000127uUEAQ;

Links.main[2].name = Text Page;

 

Links.AboutFPI[1].id = a0Y4000000127ztEAA;

Links.AboutFPI[1].name = Careers;

Links.AboutFPI[2].id = a0Y400000012803EAA;

Links.AboutFPI[2].name = Contact Us;

 

Links.TesterInfo[1].id =  a0Y40000001280DEAQ;

Links.TesterInfo[1].name =  Driving Directions;

 

Then I could set up my navigation menus by simply looping over the links structure and breaking out based on the next key, then create 1 link per array element, and use the data in that array element to actually construct the link. At least thats how it would work in a real programming language. So yeah, thats kinda what I'm thinking. Perhaps I should pull the full record set with apex, then build my nav list in JS?
Message Edited by Kenji775 on 12-03-2009 10:42 AM
sfdcfoxsfdcfox

You certainly could build it entirely in Visualforce/Apex Code (though I've not specifically done this before). The general idea would be as follows:

 

 

public class theController { public class menuItem { public List<menuItem> subMenu { get; set; } public String Label { get; set; } public String Action { get; set; } public menuItem(String newLabel, String newAction) { subMenu = new List<menuItem>(); Label = newLabel; Action = newAction; } } public List<menuItem> getMenuItems() { Map<Id,menuItem> itemMap = new Map<Id,menuItem>(); List<menuItem> mainMenu = new List<menuItem>(); // Query all menu items. Map<id,menuItem> menuMap = new map<id,WebSite_Menu__c>( [select id,ParentMenu__c,Label__c,Action__c from WebSite_Menu__c]); // Build the menu; all top-level items first. for(WebSite_Menu__c item:menuMap.values()) { if(item.ParentMenu__c==null) { itemMap.put(item.id,new menuItem(item.Label__c,item.Action__c)); mainMenu.add(itemMap.get(item.id)); } } // Remove those items from future iterations. menuMap.keySet().removeAll(itemMap.keyset()); // Recursively add items to the menu. while(!menuMap.isEmpty()) { for(WebSite_Menu__c item:menuMap.values()) { if(itemMap.containsKey(item.ParentMenu__c)) { itemMap.put(item.id,new menuItem(item.Label__c,item.Action__c)); itemMap.get(item.ParentMenu__c).subMenu.add(itemMap.get(item.id)); } } // And remove them from future iterations. menuMap.keySet().removeAll(itemMap.keySet()); } // Return the constructed menu. return mainMenu; } }

 

So, this produces an infinitely recursive menu with submenu items, etc. As an exercise to the reader, you could add ordinal values (so the menu appears in the order you specify instead of query or hash order), or other such functionality. Finally, to display the menu, you would use the following logic:

 

 

<!-- custom component 'menuItem' --> <apex:component selfClosing="true"> <apex:parameter type="theController.menuItem" name="item" required="true" /> <apex:outputLink value="{!item.Action}">{!item.Label} </apex:outputLink> <apex:repeat value="{!item.subMenu}" var="subItem"> <c:menuItem item="{!subItem}" /> </apex:repeat> </apex:component>

 

<!-- the main page --> <apex:page controller="theController"> <apex:repeat value="{!menuItems}" var="menuItem"> <c:menuItem item="{!menuItem}" /> </apex:repeat> </apex:page>

 

 

As an additional exercise to the reader, you'll need to code the component to render the subitems appropriately (i.e. when the user clicks, hovers, or maybe using indentation, etc).

If you make certain assumptions (i.e. the menu will never be more than one item deep) you can avoid writing most of the recursion logic I've outlined here, and simply have an apex:repeat inside of another apex:repeat. The core design would remain the same, however.

 

I hope that this post assists you with your endeavors.

 

 

 

Kenji775Kenji775

Thank you very much for your reply. I changed the field names around to match what I have, and it looks like a decent approach. A few questions.

 

1) In your code, what does the action field represent? I have no such field, and it's not immediatly understandable what it was supposed to do in your version.

 

2) Being an Apex class, I know I will have to test this to deploy it. How do you test something like this?

 

3) When attempting to save my modified code, I get the error
Save error: Illegal assignment from MAP:Id,SOBJECT:Website_Data__c to MAP:Id,WebsiteMenu.menuItem    WebsiteMenu.cls    Sandbox/src/classes    line 21    Force.com save problem


Unfortunatly I am borderline retarted and don't quite know how to fix that. Looks like you are perhaps trying to save the wrong kind of data into that Map, but hell if I know. Here is my code. Thanks a ton for your help, cause I really don't know what I am doing.

 

 

public with sharing class WebsiteMenu { public class menuItem { public List<menuItem> subMenu { get; set; } public String Label { get; set; } public String Action { get; set; } public menuItem(String newLabel, String newAction) { subMenu = new List<menuItem>(); Label = newLabel; Action = newAction; } } public List<menuItem> getMenuItems() { Map<Id,menuItem> itemMap = new Map<Id,menuItem>(); List<menuItem> mainMenu = new List<menuItem>(); // Query all menu items. Map<id,menuItem> menuMap = new map<id,WebSite_Data__c>( [select id,Sub_Menu__c,Page_Title__c from WebSite_Data__c]); // Build the menu; all top-level items first. for(WebSite_Data__c item:menuMap.values()) { if(item.Sub_Menu__c==null) { itemMap.put(item.id,new menuItem(item.Page_Title__c,item.Action__c)); mainMenu.add(itemMap.get(item.id)); } } // Remove those items from future iterations. menuMap.keySet().removeAll(itemMap.keyset()); // Recursively add items to the menu. while(!menuMap.isEmpty()) { for(WebSite_Data__c item:menuMap.values()) { if(itemMap.containsKey(item.Sub_Menu__c)) { itemMap.put(item.id,new menuItem(item.Page_Title__c,item.Action__c)); itemMap.get(item.Sub_Menu__c).subMenu.add(itemMap.get(item.id)); } } // And remove them from future iterations. menuMap.keySet().removeAll(itemMap.keySet()); } // Return the constructed menu. return mainMenu; } }

 

 

 

sfdcfoxsfdcfox

1) The "Action" variable represents the action when a user clicks on the navigation link. In that manner, you have both a Label (a user-friendly name) and an Action (the result from clicking the navigation link).

 

2) To test it, create a few WebSite_Menu__c objects, insert them, then construct the menu (via getMenuItems). Once you've done that, compare the results to the menu that you hypothetically built.

 

3) There's probably a small oversight in there somewhere. I didn't test the code specifically in any organization, so there's bound to be a few minor items wrong. It looks like I meant to assign a menuItem object to the map and accidentally assigned a WebSite_Data__c item instead.

 

Change:

Map<id,menuItem>

To:

Map<id,WebSite_Data__c>

The rest of the logic is basically the same.

 

You should add an Action__c or Link__c field to the menu object, or generate those based on the page title (or some such). 

Kenji775Kenji775
Thank you very much. Sorry for long delay in my reply, I've been playing around trying to get everything to work. I have the apex code saved, and that seems to be fine now. When attempting to create and save the component, I get an error stating that the command <apex:parameter> does not exist. The closest thing I could find was <apex:param> but that does not support the type attribute that you have specified. Is that "tag" depreciated? I will keep looking around to see if I can find an equivilent. All that tag did/does was to create a variable and assign it the type and value correct?
Kenji775Kenji775

Ah figured it out. I think you meant to use apex:attribute.

 

however, now I am getting the error 

 

Error: Component c:menuitem does not exist
Quick Fix

 

 

Looks like because the component is trying to refernce itself it cannot save? I really do not know. Any ideas are appreciated. Again thank you for your continue time and pateince as I stumble along trying to figure this stuff out. This whole architecture is very confusing for me. 

 

<!-- custom component 'menuItem' -->
<apex:component selfClosing="true">
<apex:attribute type="WebsiteMenu.menuItem" name="item" required="true" />

<apex:outputLink value="{!item.Action}">{!item.Page_title__c}</apex:outputLink>
<apex:repeat value="{!item.subMenu}" var="subItem">
<menuItem item="{!subItem}" />
</apex:repeat>
</apex:component>

 

 

Edit: I think I fixed the error above be removing the 

<c:menuItem item="{!subItem}" />

 and replacing it with

<menuItem item="{!subItem}" />

 but now I am getting

 Error: Unsupported type WebsiteMenu.menuItem encountered.
 Error: Apex class 'websitemenu.menuitem' does not exist

 

even though the class does exist with that name.

 

public with sharing class WebsiteMenu { public class menuItem { public List<menuItem> subMenu { get; set; } public String Label { get; set; } public String Action { get; set; } public menuItem(String newLabel, String newAction) { subMenu = new List<menuItem>(); Label = newLabel; Action = newAction; } }

 That is in my prod site. So I'm not sure what its yelling about. Ideas?

 

 

Message Edited by Kenji775 on 12-07-2009 10:38 AM
Kenji775Kenji775
Hey everyone, I don't mean to ressurect a dead thread, but I was wondering if anyone had any ideas on this. I have finally had time to come back to this project and found this ugly error waiting for me. Unfortunatly I am still confused to exactly what is going on. Any input is most appreciated. Thanks in advance.
Kenji775Kenji775

So I wanted to try a little different simpler approach, create a simple function that takes the name of the menu type, find all records with that menu type, return them as an array of Sobject and loop over those to create each menu (call the function once for each menu, there are only 4 of them). I think I got close, but I keep getting hung up on things. My new class/function/method/whatever the hell you want to call it looks like this

 

public List<WebSite_Data__c> buildMenu(string menuType) { List<WebSite_Data__c> menuItemList =([select id,Sub_Menu__c,Page_Title__c,Action__c from WebSite_Data__c where Sub_Menu__c = :menuType]); return menuItemList; }

 

 Very simple. To call it I thought I could use something like

 

 

<apex:component selfClosing="true"> <apex:attribute type="WebsiteMenu.buildMenu('About FPI')" name="item" required="true" /> <apex:repeat value="{!item}" var="subItem"> <ul><apex:outputLink value="{!item.Action}">{!item.Page_title__c}</apex:outputLink></ul> </apex:repeat> </apex:component>

 

 But no, of course not, that would make life way to easy. Instead I get the error

Error: <apex:page> is required and must be the outermost tag in the markup at line 1 column 1

Which seemed to be related to the inclusion of the <apex:component> tag. So I try removing that. I get

Error: <apex:attribute> cannot be used inside <apex:page> in the markup at line 24 column 3

 

What the hell does it want from me? Why can't I just call a function. It's so easy. I'm not trying to send a man to the goddamn moon, I just want to call a function. WHY APEX WHY?!

 

 

 

 

Jonye KeeJonye Kee
The salajeet (https://ibexsalajeet.com/) is purified using a process that removes all impurities. iii. The purified salajeet is tested in a laboratory to ensure that it meets all quality standards. 
james robert 13james robert 13

Share your Great and hilarious stories. College Dorm party (https://collegedormparty.net/) is this website as a way to share our crazy party stories with the world. We want to show everyone how much fun college can be.