3

JSLink is the greatest thing since sliced bread. Not.
There are some weird issues concerning standard stuff and I'm not sure whether these are limitations or I'm doing something wrong.

I want to have the document's title as a clickable link, not the file name. This is more beautiful considering file names such as AB2929329.pdf and a title of Joeys Earnings.

A document library list view and JSLink makes this very easy:

(function () { 
    var overrideNameField = {}; 
    overrideNameField.Templates = {}; 
    overrideNameField.Templates.Fields = {
        "Title": { "View": overrideNameFieldTemplate } 
    }; 

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideNameField); 
})(); 

function overrideNameFieldTemplate(ctx) { 

    var title = ctx.CurrentItem.Title; 
    var fileRef = ctx.CurrentItem["FileRef"];
    var fileLeafRef = ctx.CurrentItem["FileLeafRef"];

    if (title) {
        return "<a href='"+ fileRef + "'>"+ title + "</a>"; 
    }
    else {
        return "<a href='"+ fileRef + "'>"+ fileLeafRef + "</a>"; 
    }
} 

That was easy, wasn't it? The title field now always is rendered as a link - if the title is not set the default FileLeafRef is taken. This works as long as you have the FileLeafRef field also in your view or the icon (icon is fine).


I'm greedy. I not only want the title to be the link to the document, I also want the menu (...) to have a preview of the file when clicking on it via Office Web Apps. Just like FileLeafRef renders: "Filename ..." and you have all the actions on the "...".

So, all I have to do is replace "Title": { "View": overrideNameFieldTemplate } with "LinkFilename": { "View": overrideNameFieldTemplate } in the above code. Boom it works! But here comes the kicker:

It only works when I have the Title field on my list view. When I remove the field ctx.CurrentItem.Title is null. When I add the field back to the view it exists.

How can I achieve to have a clickable title of a document as well as the document menu (...)? I would love to use JSLink, but wouldn't mind using XSLT even though it has become impossible to create with the changes in SharePoint Designer 2013.

  • 3
    You're saying that if the view does not have the Title field, then the Title property of the current item is null? That sounds correct. (The current context is built from fields in the view.) – Paul Schaeflein Apr 30 '14 at 19:26
  • Can you set ListItemMenu='TRUE' in the Caml for the view to get the ellipses (...)? Then go back to "Title": { "View": overrideNameFieldTemplate }? – wjervis Apr 30 '14 at 19:31
  • ListItemMenu sounds good! Any idea how I could change it without deploying a custom list definition? SharePoint Manager? @PaulSchaeflein Bummer... Didn't know that. – Dennis G May 2 '14 at 7:39
  • I just used SharePoint Designer. How extraordinaire. @wjervis could you add your comment as an answer? ListItemMenu unfortunately does not provide document previews, but the real menu. – Dennis G May 2 '14 at 7:56
  • Got it! CalloutMenu=TRUE Awesome! Please post an answer wjervis – Dennis G May 2 '14 at 10:44
2

In order to get the Link to Item with Menu functionality on a field other than Name (Title for lists), you can modify the CAML in Designer. Add the following to the field in the <ViewFields> element: ListItemMenu='TRUE'. For example, your title field would like like:

<FieldRef Name='Title' ListItemMenu='TRUE' />

As you noted, there's a CalloutMenu attribute that will provide the document preview.

2

I did this in another manner, by strictly using JSLink. I basically hid the Title field so it wouldn't show. I did this by overriding the header. This is what i have and should get you started:

(function () {
//   Initialize the variables for overrides objects
var overrideCtx = {};
overrideCtx.Templates = {'Header': RenderTemplateWithHiddenTitleColumn};
overrideCtx.Templates.Fields = {
    'Title': { 'View': function () { return null;} },
    'LinkFilename': {
        'View': function (renderCtx) {
            if (renderCtx != null && renderCtx.CurrentFieldValue != null)
                return renderCtx.CurrentFieldValue.toString();
            return '<a href="' + ctx.CurrentItem.FileRef + '">' + renderCtx.CurrentItem.Title + '</a>';
        }
    }
};

function RenderTemplateWithHiddenTitleColumn(renderCtx, fRenderHeaderColumnNames) {
   if (renderCtx.BaseViewID == "Callout") {
       return CalloutRenderHeaderTemplate(renderCtx);
   }
   var listSchema = renderCtx.ListSchema;
    var listData = renderCtx.ListData;
    var ret = [];

    if (fRenderHeaderColumnNames == null) {
        fRenderHeaderColumnNames = true;
    }
    ret.push(RenderTableHeader(renderCtx));
    ret.push('<thead id="');
    ret.push("js-listviewthead-" + renderCtx.wpq);
    ret.push('"><tr valign="top" class="ms-viewheadertr');
    if (fRightToLeft)
        ret.push(' ms-vhrtl');
    else
        ret.push(' ms-vhltr');
    ret.push('">');
    if (listSchema.TabularView != undefined && listSchema.TabularView == "1") {
        ret.push('<th class="ms-headerCellStyleIcon ms-vh-icon ms-vh-selectAllIcon" scope="col">');
        RenderSelectAllCbx(renderCtx, ret);
        ret.push('</th>');
    }
    if (fRenderHeaderColumnNames) {
        var fields = listSchema ? listSchema.Field : null;
        var counter = 1;

        for (var f in fields) {
            var field = fields[f];
            if (field.Name == "Title") {
                ret.push("<th></th>");
                break;
            };
            if (field.DisplayName == null)
                continue;
            if (field.GroupField != null)
                break;
            field.counter = counter++;
            ret.push(spMgr.RenderHeader(renderCtx, field));
            if (IsCSRReadOnlyTabularView(renderCtx) && (field.CalloutMenu == "TRUE" || field.listItemMenu == "TRUE"))
                ret.push("<th></th>");
        }
    }
    if (listSchema.TabularView == "1" && renderCtx.BasePermissions.ManageLists && renderCtx.ListTemplateType != 160) {
        ret.push('<th class="ms-vh-icon" scope="col" title=""><span class="ms-addcolumn-span"> </span></th>');
    }
    ret.push("</tr>");
    ret.push("</thead>");
    return ret.join('');
};

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

I had to do a couple workarounds, nothing too big. I had issues with the Callout menu when overriding the header, so i simply called the default CalloutRenderHeaderTemplate function if the BaseViewID was Callout

if (renderCtx.BaseViewID == "Callout") {
   return CalloutRenderHeaderTemplate(renderCtx);

}

In the loop when rendering the columns, i simply escaped when the Title field came up:

if (field.Name == "Title") {
            ret.push("<th></th>");
            break;
};

So far its working pretty well and i haven't noticed any issues. Hope this helps!

1

Because I started with this question as a reference point, I just wanted to link to a solution I came up with in case it helps anyone else attempting this same thing.

Do not apply CSR Override in QuickEdit Mode

I built on the JSLink method but had some issues when switching from normal to QuickEdit mode.

Now I have managed to override just the bits of the header and body that hide the Title column while passing through the default render functions when switching to Quickedit.

Hopefully the script is useful in conjunction with the answers on this page for anyone grappling with this same problem :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.