Portal Engine Questions on portal engine and web parts.
Version 6.x > Portal Engine > Creating Webparts View modes: 
User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/15/2012 9:15:31 AM
   
Creating Webparts
I've created a custom webpart that has a textbox, button and a CMSRepeater on it. When the button is clicked it gets the search text from the textbox and sends the value to a web service and then binds a datatable of results from the web service to the CMSRepeater (which has transformations specified).

Now I want to be able to click into the details of an item. Keep in mind these aren't "documents" they are records I receive from a web service outside of my site. My webpart file is called Locations.ascx (displays the list) and I have a LocationsDetail.ascs control that displays all the locations details (image, demographics, amenities, etc.). How do I navigate from one to the other? Typically, I'd use GetDocumentUrl() but since this isn't a document, I'm not sure which way to go.

User avatar
Kentico Consulting
Kentico Consulting
kentico_borisp - 3/16/2012 3:57:05 AM
   
RE:Creating Webparts
Hello,

Now it depends on you how to display the data. If the details of an entry are also retrieved through a service, then you can create a dynamic page which will retrieve the correct data according to the query parameter or you can use wildcards. These query parameters will be passed to the page when you click on a transformation link.

Best regards,
Boris Pocatko

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/16/2012 11:33:28 AM
   
RE:Creating Webparts
The details will require another web service call based on the location selected. I think I'm following you but let me show what I've done so far.

I've created the webpart (ascx), added the properties in code, added the webpart and properties to Site Manager>Development>Web Parts, added a transformation. Here is my simple code for my webpart (of course I've added some properties as well for paging, transformations, etc)


<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Locations.ascx.cs" Inherits="CMSWebParts_Test_Locations" %>

<cms:LocalizedLabel ID="lblCity" runat="server" ResourceString="locations.city" />
<asp:TextBox ID="TextBox1" runat="server" />

<cms:LocalizedDropDownList ID="ddlStates" runat="server">
<asp:ListItem Text="IA" Value="IA" />
<asp:ListItem Text="MN" Value="MN" />
<asp:ListItem Text="WI" Value="WI" />
</cms:LocalizedDropDownList>
<cms:LocalizedLinkButton ID="btnSearch" runat="server" ResourceString="locations.search" OnClick="btnSearch_Click" /><br /><br />
<cms:CMSRepeater ID="repItems" runat="server" />


#region "Methods"

/// <summary>
/// Content loaded event handler
/// </summary>
public override void OnContentLoaded()
{
base.OnContentLoaded();
SetupControl();
}


/// <summary>
/// Initializes the control properties
/// </summary>
protected void SetupControl()
{
if (this.StopProcessing)
{
// Do nothing
}
else
{
// Document properties
repItems.NestedControlsID = NestedControlsID;

// Pager
repItems.EnablePaging = EnablePaging;
repItems.PageSize = PageSize;
repItems.PagerControl.PagerPosition = PagerPosition;
repItems.PagerControl.QueryStringKey = QueryStringKey;
repItems.PagerControl.PagingMode = PagingMode;
repItems.PagerControl.BackNextLocation = BackNextLocation;
repItems.PagerControl.ShowFirstLast = ShowFirstLast;
repItems.PagerControl.PagerHTMLBefore = PagerHTMLBefore;
repItems.PagerControl.PagerHTMLAfter = PagerHTMLAfter;
repItems.PagerControl.ResultsLocation = ResultsPosition;
repItems.PagerControl.PageNumbersSeparator = PageNumbersSeparator;

// Transformation properties
repItems.TransformationName = TransformationName;
repItems.SelectedItemTransformationName = SelectedItemTransformationName;
repItems.AlternatingTransformationName = AlternatingTransformationName;

// Public properties
repItems.HideControlForZeroRows = HideControlForZeroRows;
repItems.ZeroRowsText = ZeroRowsText;
repItems.ItemSeparator = ItemSeparator;
}
}

/// <summary>
/// Reloads data.
/// </summary>
public override void ReloadData()
{
base.ReloadData();
SetupControl();
repItems.ReloadData(true);
}

/// <summary>
/// OnPrerender override (Set visibility).
/// </summary>
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);

Visible = !repItems.StopProcessing;

if (DataHelper.DataSourceIsEmpty(repItems.DataSource) && (repItems.HideControlForZeroRows))
{
Visible = false;
}
}

#endregion

#region "Events"
/// <summary>
/// Gets the data from the webservice and binds it to the repeater
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnSearch_Click(object sender, EventArgs e)
{
MyWebService.RetailStructure.RetailStructureService rss = new MyWebService.RetailStructure.RetailStructureService();
MyWebService.RetailStructure.ServiceCallResult scr = rss.GetStoreDataByProximityToCityAndState("Kentico", TextBox1.Text.Trim(), ddlStates.SelectedValue);

if (!scr.HasErrors)
{
repItems.DataSource = scr.DataSetResults.Tables[0];
repItems.DataBind();
}
}

#endregion


Transformation:

<div style="padding: 5px;">
<div style="float: left; width: 50%;">
#<%# Eval("StoreNumber") %> </b> <br />
<%#Eval("Address1") %><br />
<%#Eval("City") %>,
<%#Eval("ST") %>
<%#Eval("Zip") %>
</div>
<div style="float: right; width: 50%;">
<a href="#">Directions</a><br />
<a href='#'>Store Info</a><br />
<a href='#'>Add to My Stores</a>
</div>
<div style="clear: both;"></div>
</div>

This all works great and displays everything I wanted with 2 exceptions:

* Unable to get a link to work to view the details. Those would be different ascx files I'm guessing or a transformation, not sure.

* Unable to get paging to work

User avatar
Kentico Consulting
Kentico Consulting
kentico_borisp - 3/19/2012 11:14:41 PM
   
RE:Creating Webparts
Hello,

As I said earlier, you need to create the page with details dynamically and so the link. For example, your dynamic Kentico page as the URL:

www.mydomain.com/pages/{id}.aspx

The id specifies the content and is used to retrieve it with your web service call. This needs to be done in code behind of a web part. With which part are you having difficulties?

What do you mean by having problems paging to getting work? Have you tried to set the properties of the repeater pager in the designer file instead of in the code behind with some static values?

Best regards,
Boris Pocatko

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/20/2012 8:41:34 AM
   
RE:Creating Webparts
Here is what I've tried in the designer for the paging with no luck:

<cms:CMSRepeater ID="repItems" runat="server" PageSize="20" PagerControl-PagerPosition="TopAndBottom" PagerControl-Enabled="true" PagerControl-PagingMode="QueryString" PagerControl-ShowFirstLast="true" PagerControl-ResultsLocation="Bottom" />

As far as the dynamic page, still new with developing in Kentico (and especially webparts) so my confusion is with where do I create this dynamic page, in code behind, in the CMSDesk or where? Do you have any examples?

User avatar
Kentico Consulting
Kentico Consulting
kentico_borisp - 3/21/2012 3:15:33 AM
   
RE:Creating Webparts
Hello,

I would suggest you to check out the CMSRepeater definition in this forum thread. I think you are missing the transformation definition for the pager.

Please check this documentation regarding the dynamic page question.

Best regards,
Boris Pocatko

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/21/2012 9:10:42 AM
   
RE:Creating Webparts
Boris, thanks for the links although they were of limited help.

I set the transformation for the repeater in code behind with public properties and then define it in the UI when adding the webpart to the page and that works fine. I have not seen any property that defines a pager transformation for the repeater.

I already use document aliases with custom URL's for membership profiles, etc although those are predefined modules/webparts and I'm not seeing how to set/get the URL parameter in code behind to assign it in my web service. For instance this setup:

<root>/Search/Details

On the Details page I have this custom URL setup, /Search/{StoreNumber}. I've created the URL from the Search page to the details page by setting the URL in the repeater transformation. How do I, on the details page, then capture the {StoreNumber} parameter in the URL in code behind? I've searched through the developer and API documentation and have not found it.

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/21/2012 1:25:34 PM
   
RE:Creating Webparts
From what I can see the reason the paging isn't working is because the default path is set to get everything below my current document (which is the details page). The paging doesn't take into effect the actual rows the datasource has. This simple button click event is where the search and databind happen.


protected void btnSearch_Click(object sender, EventArgs e)
{
MyWebService.RetailStructure.RetailStructureService rss = new MyWebService.RetailStructure.RetailStructureService();
MyWebService.RetailStructure.ServiceCallResult scr = rss.GetStoreDataByProximityToCityAndState("Kentico", TextBox1.Text.Trim(), ddlStates.SelectedValue);
if (!scr.HasErrors)
{
repItems.DataSource = scr.DataSetResults.Tables[0];
repItems.DataBind();
}
}

So there has to be a way to do this and get paging to work properly with setting the repeaters datasource dynamically. Looking for any suggestions on this.

User avatar
Kentico Consulting
Kentico Consulting
kentico_borisp - 3/22/2012 4:10:42 AM
   
RE:Creating Webparts
Hello,

I tried to dig around a bit and it seems that you need to delay the processing of the repeater:


<cms:cmsrepeater ID="rpTags" runat="server" TransformationName="CorporateSite.Transformations.user" DelayedLoading="true" />




Afterwards you populate it in the code behind the following way:

protected void Page_Load(object sender, EventArgs e)
{

this.rpTags.DataSource = UserInfoProvider.GetAllUsers();
this.rpTags.EnablePaging = true;
this.rpTags.PageSize = 3;

this.rpTags.DataBind();
}


I am sorry for the confusion about the pager transformation. Regarding the issue of getting the wildcard in your code behind. You can use simply get the query string according to your wildcard:

this.Request.QueryString["test"]

In this case the wildcard is {test}.

Best regards,
Boris Pocatko

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/22/2012 10:02:41 AM
   
RE:Creating Webparts
Didn't even think to use the Request.QueryString method, worked great.

Your example with delayed loading worked although when I move from page to page now I lose the results. Guessing I have to specify which set of records to get when I bind my datasource correct?

So two steps forward and one back, my link to get to details is not working now. I use the GetDocumentUrl() to build out the link to the dynamic page but it continues to put /default.aspx in anytime I use the GetDocumentUrl() method. Is this because of the way I am databinding with my webservice and they aren't physical documents in the database? When I look at Request.Url it returns http://localhost/CMSPages/PortalTemplate.aspx?aliaspath=/pagename-here. Do I need to parse out the query string or is there already a method for this aside from the GetDocumentUrl()?

User avatar
Kentico Legend
Kentico Legend
Brenden Kehren - 3/22/2012 1:17:36 PM
   
RE:Creating Webparts
Answered my own question, used Request.RawUrl to get what I needed in replacement of the GetDocumentUrl() function.

User avatar
Kentico Consulting
Kentico Consulting
kentico_borisp - 3/26/2012 1:48:48 AM
   
RE:Creating Webparts
Hello,

For me is the pagination working fine. I assume, you are losing the page state because you are populating the web part by a button click. Thus, this action isn't performed by a page refresh, only if a button is clicked. You will have to save the state somehow (e.g. query string) and restore it.

Best regards,
Boris Pocatko