1

I've tried my best not to ask for help, but I'm stuck, even after I learned a bit of JS, MomentJS and Client Side Rendering on SP.

The code below returns undefined in date column. If you know why, please let me know.

// JavaScript Document
(function () {
var condFieldCtx = {};
// Define template variable  
condFieldCtx.Templates = {};
// Define your required fields and functions to call in each case.
// In our case the field is Progress
// Override Function is PatientProgressViewTemplate
condFieldCtx.Templates.Fields = {
    "Priority": {"View": PriorityFormat},
    "PercentComplete": {"View": PercentCompleteFormat},
    "b05o": {"View": CreateDateFormat}     
};
//conditional formatting for a complete row comes here
condFieldCtx.OnPostRender = [HighlightRowOverride];
// Register the template override with SP2013 
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(condFieldCtx);
})();

function CreateDateFormat(ctx)
{
var date = new Date();
var CreateDate = moment(ctx.CurrentItem.CreateDate).format('DD/MM/YYYY');
var now = moment().format('DD/MM/YYYY');
//Compare and react
if(now > CreateDate)
{
return "<span><font style='background-
color:red;display:block;'>"+ctx.CurrentItem.CreateDate+"</font>";
}
else if(now == CreateDate)
{
return "<span><font style='background-
color:yellow;display:block;'>"+ctx.CurrentItem.CreateDate+"</font></span>";
}
else
{
return ctx.CurrentItem.CreateDate;
}
}

Everything else works fine, as you can see below on the screenshot. It's just the dates I'm struggling with.

Please tell me what am I doing wrong.

enter image description here




Edit1:

OK, thanks to Danny, I finally got it sorted. I hope.

Below is the working code; ctx.CurrentItem.ColumnName reference had to be changed to the internal name b05o, some tweaking here and there..

function CreateDateFormat(ctx)
{
var CreateDate = moment(ctx.CurrentItem.b05o).format('DD/MM/YYYY');
var now = moment(date, "L", 'en-GB', true).format('DD/MM/YYYY');
//Compare and react
if(CreateDate == 'undefined' || !CreateDate)
{
return ctx.CurrentItem.b05o;
}
else if(now > CreateDate)
{
return "<span><font style='color:white;background-color:red;display:block;'>"+ctx.CurrentItem.b05o+"</font>";
}
else if(now == CreateDate)
{
return "<span><font style='background-color:yellow;display:block;'>"+ctx.CurrentItem.b05o+"</font></span>";
}
else if(now < CreateDate)
{
return "<span><font style='color:white;background-color:green;display:block;'>"+ctx.CurrentItem.b05o+"</font></span>";
}
else
{
return ctx.CurrentItem.b05o;
}
}  

...and here's the result and working date formatting.

enter image description here

The only worry I have is the format of the date displayed in debugging:

enter image description here

The date entered in Item 6 is 31/12/2017 and as you can see it's formatted as green on the list, which is correct, but console.log shows it as 12/07/2019. Below, 05/06/2017 and 06/05/2017

console.log(now > CreateDate);

is displayed as true in debugger. Possibly not a big deal, but I'm worried that something is still nor right and it might cause issues in future.

Last problem I have is when I Stop editing the list I get the following error:

enter image description here

Not sure what to do with this :]

Edit2:

Danny showed me great and simple way for authoring the views live, but date 31/12/2017 still seems to be causing issues. It returns invalid date, probably because 12/31/2017 is invalid.

enter image description here

Edit3:

I had to fiddle with dates a bit to get it working, and here's what I did:

  "b05o": {
 View: function (ctx) {
 var valueU = ctx.CurrentItem[this.Name].split("/");
 var valueY = valueU[1] + "/" + valueU[0] + "/" +valueU[2];
 var valueM = moment(valueY).format('DD/MM/YYYY');
 var valueT = new Date(valueY);
 var daysDiff = GetDaysAfterToday(valueT);
 var color = '#ff6600';            // today dark orange
 if (daysDiff > 0) color = 'green';    // future green
 if (daysDiff < 0) color = 'red';  // past red
 if (daysDiff > 0 && daysDiff < 30) color = '#ffad33'; //next 30 days turns orange
 return String.format('<span style=background:{0};color:white>{1:d}</span>',color,ctx.CurrentItem[this.Name]);
}

And this is what I get:

enter image description here

Maciek
  • 115
  • 1
  • 12
  • use console.log(ctx.CurrentItem) and you will spot your error – Danny '365CSI' Engelman May 06 '17 at 16:52
  • Thanks Danny for guiding me in the right direction. All is working now, but, two things: 1. debugging shows me some weird things and 2. When I stop editing the list I get TypeError. I'd appreciate if you could guide me in the correct direction on this one :) I added new info to the main post. – Maciek May 06 '17 at 20:13
  • Your second moment function has a date variable; but where does that come from? The error could come from other SP code, check line numbers and filenames – Danny '365CSI' Engelman May 07 '17 at 09:56
  • The missing Date variable was deleted by mistake when editing post. (It's there now). There problem with date 31/12/2017 still exists though :( – Maciek May 07 '17 at 19:44
  • What code do you log to display those incorrect dates? Must be a formatting or dateoffset issue – Danny '365CSI' Engelman May 07 '17 at 19:55
  • @Danny'365CSI'Engelman I edited the original post with a new screenshot. The list shows NaN/NaN/NaN and console.log shows Invalid date in debugging. – Maciek May 07 '17 at 20:05
  • and new Date(moment(ctx.CurrentItem[this.Name], "L", 'en-GB', true)) ? – Danny '365CSI' Engelman May 08 '17 at 07:04
  • Hi Danny, no this bit of code didn't do anything actually. Momentjs loaded correctly. Even though some dates appear to be displayed correctly, the code still thinks 08/05/2017 is August 5th and hence 31/12/2017 is invalid. I'm trying to swap DD with MM or even convert the date to String and then back to Date, but so far I've had no luck :/. What is going on with them dates... – Maciek May 08 '17 at 13:55
  • I just checked on the momentJS site, you need a lowercase L: new Date(moment("5/8/2017", "l", 'en-GB', true)) returns: Sat Aug 05 2017 00:00:00 GMT+0200 (W. Europe Daylight Time) – Danny '365CSI' Engelman May 08 '17 at 14:17
  • I had to fiddle with dates a bit to get it working. Take a look at the code above - only now it will do what I wanted it to do, I edited the post again and changed the title as well. How do I attach both moment.js and my custom.js files on one page? Can I do it via html web part? – Maciek May 09 '17 at 09:49
  • You can add them in JSLink property of the WebPart to apply to one page, or Install the SharePoint Editor Chrome Extension, and load them both as UserCustomAction ScriptLinks, for explanation look for John Lui's blog on UserCustomActions... BTW, you should/must use the Cisar Chrome Extension for CSR, it does half the work fr you, like managing JSLink for your custom.js, you still have to load momentJS yourself, Cisar does not take care of 3rd party libraries... then mark my answer so your question is marked as having an answer – Danny '365CSI' Engelman May 09 '17 at 10:11
  • Danny, I followed instructions on both SP editor and Cisar, I loaded moment.js and mycustom.js files, both successfully linked to the webpart, but when page is refreshed, the formatting isn't applied :/. Is there anything else I should know about? – Maciek May 09 '17 at 14:41
  • F12 dev console is your friend, watch for errors there, if you don't see errors (relating to your code) your code is wrong. Paste it into another StackOverflow question, so others can help as well – Danny '365CSI' Engelman May 09 '17 at 14:52
  • Yes, F12 is obviously very helpful, and one missing curly bracket... fixed all my problems and now that everything works, I get to understand how amazing Cisar and SP Editor tools are :). My boss will love what's coming, but I'm sure I'll be back with more ideas/questions :], Thanks, Danny. – Maciek May 09 '17 at 22:31

1 Answers1

1

Good, you found the issue with the internal name yourself, that is always the best way to make learning stick.

Some tips

  • avoid creating new List Fields with that "easy" SharePoint UI, that's how you get those stupid weird internal names.
    Instead create new Fields in the List settings, where you specify the Internal name first (without spaces!), then rename the column to give its DisplayName (the first name will stick as Internal Name)

  • Always use Chrome and the Cisar WYSIWYG CSR editor when editing CSR files

  • Don't hardcode fieldnames, the fieldname the function was called on is in the this JavaScript Scope as this.Name

  • No need for the MomentJS library
    If you only do simple date calculations, SharePoint provides a GetDaysAfterToday() function

  • Try to write as less repeating code as possible, keeps your code readable and easy maintainable
    The only string different in your long 3 SPAN lines is the color

  • SharePoints' String.format() method is very helpful to include parameters in Strings
    And can format Dates to anything you want: Changing date format using javascript

  • The <font> tag is no longer supported in HTML5, you set the style on the parent element


You code becomes something like:

"b05o": {
    View: function (ctx) {
     var value = new Date(ctx.CurrentItem[this.Name]);
     var daysDiff = GetDaysAfterToday(value);
     var color = 'yellow';            // today
     if (daysDiff > 0) color = 'red';    // future
     if (daysDiff < 0) color = 'green';  // past
     return String.format('<span style=background:{0};color:white>{1:d}</span>',color,value);
    }

notes

  • style has no double-quotes
    because DOM element attributes (without spaces) will be quoted (with ") by the browser
    so you don't have to specify them in your code (unless they have spaces)
Danny '365CSI' Engelman
  • 21,176
  • 7
  • 35
  • 79