TitleURL in DataType

Topics: General
Jul 13, 2012 at 2:44 PM
Edited Jul 16, 2012 at 9:36 PM

Hello,

Can I have a custom DataType with a TitleURL field that is automaticly populated with a valid UserFriendly URL based on the Title field?

It's like in the "News" package, but I can't figure out how it's done.

Edited: by accident I wrote Date Type, it has to be "DataType".

Jul 15, 2012 at 11:28 AM

Yes you can. Achieving it depends on what page structure you are using.

The C1 XSLT template page creation method automatically adds a Page Title attribute (<rendering:page.title />) and a META Title attribute (<meta name="title" content="Composite.Rendering:page.title" />).   

The C1 Core Renderer (http://compositec1.codeplex.com/SourceControl/changeset/view/18891#155095) generates the above fields and the URL based on the data stored in your sites ~\App_Data\Composite\DataStores\Composite.Data.Types.IPage_Published.xml  data store which includes 'FriendlyUrl' in the following fields:

<PageElements PublicationStatus="published" ChangeDate="" ChangedBy="" CultureName="" SourceCultureName="" Id="" TemplateId="" PageTypeId="" Title="" MenuTitle="" UrlTitle="" FriendlyUrl="" Description="" />

So you could conceivably create a method which injects your UserFriendly URL into the above IPage datastore within the FriendlyUrl=""  field after the page is created. Then leave it to the Core Renderer to output your desired URLs   

Also See : http://compositec1.codeplex.com/discussions/252143 
http://compositec1.codeplex.com/discussions/267721 
http://docs.composite.net/Data/Adding-pages-with-Csharp 

However, if you are generating your own pages without using the C1 dashboard's content page creator wizard, then taking control of the URL based on Title creation is where your own DataType could be needed if you want it specifically stored. The least you would need is data fields including "Page ID" to record the IPage and a field "TitleURL".

The alternative would be to create a class to override the Core Renderer and dynamically create the FriendlyURL based on the IPage Title field using a regex type formatting template to convert the Title spaces into dashes etc for the URL. 

Jul 17, 2012 at 7:37 AM

webasylum, I'm not using Pages, but a global Datatype. I have imported a few hundred items into Composite using a Global Datatype. I allready created the Friendly URL using a regex formatting template on import. But when an editor is adding new items to the Global Datatype using the Console, the Friendly URL should also be automaticly converted and saved.

I think my question is how to attach an action to the Console form upon save of the Datatype item.

Coordinator
Jul 19, 2012 at 11:00 AM

Hi Marco

Use OnBeforeUpdate and OnBeforeAdd data events to fill up the field value if it is empty.

You can find the examples here

http://docs.composite.net/Data/DataFAQ?q=How+to+attach+events+to+Composite+C1+Data+Stores%3F

P.S. At the moment we're experiencing problems with our hosting environment, so the style sheets on docs.composite.net may not be loaded properly.

Aug 15, 2012 at 11:53 AM
Edited Aug 15, 2012 at 11:57 AM

hi napernik,

A bit of a delayed reply. I've read the examples in your link and I managed to do some logging. But when it comes to changing the code to my need I am clueless...

I have this code so far:

 

public static class CreateUserFriendlyURL
{
    static CreateUserFriendlyURL()
    {
        DataEvents<IData>.OnBeforeUpdate += new DataEventHandler(MyDataBeforeUpdate);
    }
    public static void Initialize()
    {
    }

    private static void MyDataBeforeUpdate(object sender, DataEventArgs dataEventArgs)
    {

        IData item = (IData)dataEventArgs.Data;

        // here I need to know if the Data is of the Type JWL.Data.Digibieb
// then get the Title, change it to userfriondly URL like "toUrlFormat(item.Title)"
// and finally save it to the FriendlyUrl field.

} public static String toUrlFormat(String strToReplace) { strToReplace = @Regex.Replace(strToReplace, @"<(.|\n)+?>", ""); strToReplace = @Regex.Replace(strToReplace, @"[^a-zA-Z0-9_ ]+", ""); strToReplace = strToReplace.ToLowerInvariant(); strToReplace = strToReplace.Replace(" ", "-"); return strToReplace; } }
Coordinator
Aug 15, 2012 at 1:18 PM

Hi Marco

you need something like that:

            var myData = item as JWL.Data.Digibieb;
            if(myData == null) return;

            if (string.IsNullOrEmpty(myData.TitleURL))
            {
                myData.TitleURL = toUrlFormat(myData.Title)
            }

 

notice that you don't have to save the changes as those events are occurring before the actual "save" event so the will be saved.

you should also subscribe to OnBeforeAdd event. I'm not sure if changes to TitleURL field will be shown immediately in the editor, so it may be showing the field only when you open it in the second time.

Aug 15, 2012 at 1:56 PM

Hi napernik,

Thank you! A also added the OnBeforeAdd event and I will hide the TitleUrl field form the form in the editor.

This is the complete code I came up with. Any sugestions left?

public static class CreateUserFriendlyURL
{
    static CreateUserFriendlyURL()
    {
        DataEvents<IData>.OnBeforeUpdate += new DataEventHandler(MyDataBeforeUpdate);
        DataEvents<IData>.OnBeforeAdd += new DataEventHandler(MyDataBeforeAdd);
    }

    public static void Initialize()
    {
        // initialization code is in the static constructor
    }

    private static void MyDataBeforeUpdate(object sender, DataEventArgs dataEventArgs)
    {

        IData item = (IData)dataEventArgs.Data;
        var myData = item as JWL.Data.Digibieb;
        if(myData == null) return;

        myData.TitleUrl = toUrlFormat(myData.Title);
        // LoggingService.LogInformation("CreateUserFriendlyURL", toUrlFormat(myData.Title));

    }

    private static void MyDataBeforeAdd(object sender, DataEventArgs dataEventArgs)
    {

        IData item = (IData)dataEventArgs.Data;
        var myData = item as JWL.Data.Digibieb;
        if (myData == null) return;

        myData.TitleUrl = toUrlFormat(myData.Title);
        // LoggingService.LogInformation("CreateUserFriendlyURL", toUrlFormat(myData.Title));

    }

    public static String toUrlFormat(String strToReplace)
    {
        strToReplace = @Regex.Replace(strToReplace, @"<(.|\n)+?>", "");
        strToReplace = @Regex.Replace(strToReplace, @"[^a-zA-Z0-9_ ]+", "");
        strToReplace = strToReplace.ToLowerInvariant();
        strToReplace = strToReplace.Replace(" ", "-");
        return strToReplace;
    }

}

Coordinator
Aug 15, 2012 at 3:03 PM
Edited Aug 15, 2012 at 3:06 PM

If it's not working also check that Initialize() is actually invoked. You can do it either from global.asax or with using an ApplicationStarup attribute.

In DataEvents<T> you can specify the data type as a parameter: DataEvents<JWL.Data.Digibieb>

So it should look like:

 

public static class CreateUserFriendlyURL
{
    static CreateUserFriendlyURL()
    {
        DataEvents<JWL.Data.Digibieb>.OnBeforeUpdate += MyDataBeforeAddOrUpdate;
        DataEvents<JWL.Data.Digibieb>.OnBeforeAdd += MyDataBeforeAddOrUpdate;
    }

    public static void Initialize()
    {
        // initialization code is in the static constructor
    }

    private static void MyDataBeforeAddOrUpdate(object sender, DataEventArgs dataEventArgs)
    {

        IData item = (IData)dataEventArgs.Data;
        var myData = item as JWL.Data.Digibieb;
        if(myData == null) return;

        myData.TitleUrl = toUrlFormat(myData.Title);
        // Log.LogInformation("CreateUserFriendlyURL", toUrlFormat(myData.Title));

    }

    public static String toUrlFormat(String strToReplace)
    {
        strToReplace = @Regex.Replace(strToReplace, @"<(.|\n)+?>", "");
        strToReplace = @Regex.Replace(strToReplace, @"[^a-zA-Z0-9_ ]+", "");
        strToReplace = strToReplace.ToLowerInvariant();
        strToReplace = strToReplace.Replace(" ", "-");
        return strToReplace;
    }

}
Aug 16, 2012 at 6:46 AM

Great and many thanx! This can be so usefull in other projects.