Calculating age by birthdate field in crm 2013 - dynamics-crm

I need to write a global javascript code that calculates age by birthday field and call the function from a diffrent javascript file to the specific entity.
from some reason i get error message "CalculateAge is undefined" after i loaded my entity javascript file to the form.
This is what i write in the global file:
CalculateAge: function (birthd)
{
if (birthd == null) {
return;}
var today = new Date().getFullYear();
year1 = birthd.getFullYear();
return (today-year1);
}
This is what i write in my entity file that i am loading to the form:
function onLoad() {
var birthDate = Xrm.Page.getAttribute("el_birth_date").getValue();
Xrm.Page.getAttribute("el_age").setValue(CalculateAge(birthDate));
}
I am new in Javascript.. Can ypu please help?

The JavaScript code you are using to calculate the age is not correct, it doesn't consider the month and the day.
A correct version is this one:
function CalculateAge(birthday, ondate) {
// if ondate is not specified consider today's date
if (ondate == null) { ondate = new Date(); }
// if the supplied date is before the birthday returns 0
if (ondate < birthday) { return 0; }
var age = ondate.getFullYear() - birthday.getFullYear();
if (birthday.getMonth() > ondate.getMonth() || (birthday.getMonth() == ondate.getMonth() && birthday.getDate() > ondate.getDate())) { age--; }
return age;
}
and can be used as:
var birthday = Xrm.Page.getAttribute("new_birthday").getValue();
var age = CalculateAge(birthday);
alert(age);
// age on 1st January 2000, JavaScript Date() object contains months starting from 0
var testdate = new Date(2000, 0, 1, 0, 0, 0);
var testage = CalculateAge(birthday,testdate);
alert(testage);
If you get CalculateAge is not defined, probably you didn't include the webresource containing your function inside the form. If you have two JS web resources (one containing the function, the other one containing the onLoad event) both need to be included inside the form.
If you are in a CRM version that has the issue of the asynchronous javascript loading, it's better to include the CalculateAge function in the same file as the onLoad event, but if you prefer keep them separate check this blog post: Asynchronous loading of JavaScript Web Resources after U12/POLARIS
The JavaScript function comes from my blog post: Calculate age in Microsoft Dynamics CRM 2011

Related

Get Student Submissions from Google Classroom

Goal: use Google App Script to get {link:url} and {driveFile:alternativeLink} from student submissions (attachments) to a Google Classroom Assignment.
Issue: While I can get all of the attachments, I cannot filter down to the specific type of attachment or it's respected property. Specific types of attachments return 'undefined'. Any help would be greatly appreciated.
I can get the the desired results using the Classroom API website by adding to the "field" input:
studentSubmissions.assignmentSubmission.attachments.driveFile
https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions/liststrong text
function testStudSubs(){
console.log(getStudSubs());
}
function getStudSubs(){
const COURSE_ID = "60005382479";
const COURSE_WORK_ID = "141252225149";
const USR_ID = {userId:"105308051639096321984"};
const ID = "Cg0IhMWczB0Q_dCnmo4E";
const submissions = Classroom.Courses.CourseWork.StudentSubmissions.list(COURSE_ID, COURSE_WORK_ID, USR_ID).studentSubmissions
return submissions.map(submission => {
return `${submission.assignmentSubmission.attachments}`
});
}
Answer: (Special thanks to Yagisanatode.com for pointing me in the correct direction.)
1st: ensure proper scopes have been added...see response from Sourabh Choraia stackOverflow response. The scopes will ensure we have access to the objects. Once we request a specific object (ex: link or driveFile), attachments that are not of that object type will display as undefined.
2nd: we need to remove the undefined objects. To do this, we can following w3resource (javascript version), adding the format to our "test" function (w3resource example).
We also need to tweak the array by flattening it. Flattening the array will show the correct length by including the undefined objects.
Finally, for the result, we will map it and pull the desired property (Google Api - Student Submissions List).
Here is working example:
function testStudSubs(){
console.log(getStudSubs());
console.log(getStudSubs().length);
console.log(getStudSubs().flat(2)); // creates separate object for each...ex: 4
const myFlat = getStudSubs().flat(2);
let index = -1;
const arr_length = myFlat ? myFlat.length : 0;
let resIndex = -1;
const result = [];
while (++index < arr_length) {
const value = myFlat[index];
if (value) {
result[++resIndex] = value;
}
}
console.log(result.map(result => { return result.alternateLink + `:` + result.title}));
return result.map(result => { return result.alternateLink + `:` + result.title});
}
/*/////////////////////////////
/
/ Pulls student submitted work from Classroom
/
*//////////////////////////////
function getStudSubs(){
const COURSE_ID = "60005382479"; // update
const COURSE_WORK_ID = "141252225149"; //update
const USR_ID = {userId:"105308051639096321984"}; //update
const submissions = Classroom.Courses.CourseWork.StudentSubmissions.list(COURSE_ID, COURSE_WORK_ID, USR_ID).studentSubmissions
return submissions.map(submission => {
return submission.assignmentSubmission.attachments.map(attachments =>
{
return attachments.driveFile
});
});
return submissions
}

Problem listing assignments of a student in Google Classroom

I am starting to use Classroom API to enhance local apps in our school. In order to make a report for a class, I want to list all student assignments and gradings. I use loops to go through all courses for a student, then all coursework for every course, and then all submissions for every coursework. Here is the piece of code that I use:
function fListWorkStudent(idStudent)
{
// Variables
var pageToken = null;
var optionalArgs =
{
pageToken: pageToken,
courseStates: 'ACTIVE',
studentId: idStudent,
pageSize: 0
};
var optionalArgs2 =
{
pageToken: pageToken,
userId: idStudent,
pageSize: 0
};
// Courses for a student
var response = Classroom.Courses.list(optionalArgs);
var sCourses = response.courses;
if (sCourses.length === 0)
Logger.log("No courses");
else
{
for (course in sCourses)
{
var idCourse=sCourses[course].id;
var nomprof=getUserName(sCourses[course].ownerId);
// Coursework for every course
var responseW = Classroom.Courses.CourseWork.list(idCourse);
var works = responseW.courseWork;
if (works && (works.length > 0))
{
for work in works)
{
var idWork=works[work].id;
// Submissions for every coursework
var responseS = Classroom.Courses.CourseWork.StudentSubmissions.list(idCourse, idWork, optionalArgs2);
var submissions = responseS.studentSubmissions;
if (submissions && submissions.length >0)
{
for (submission in submissions)
{
// Prepare report here
}
}
}
}
}
}
}
The problem with this code is that when I call Classroom.Courses.CourseWork.StudentSubmissions.list(idCourse, idWork, optionalArgs2) to get the submissions filtered of selected student, and the loop reaches a coursework not assigned to that student, the call fails with error 'classroom.courses.courseWork.studentSubmissions.list; error: Requested entity was not found.'
I could solve it by checking in the loop if the coursework is not assigned to that student before calling the API function, or maybe using a try..catch clause to catch the possible error, but I would like to know if there is a smarter solution to this issue.
Regards
Rafael
Unfortunately the API does not give you an endpoint to list directly all assignment / submissions of a given student
However, you are not alone with this problem, there is already a feature request for this functionality on Google's Public Issue Tracker.
I recommend you to give it a "star" in order to increase visibility.
In the mean time, indeed you either need to implement a try...catch statement, or a conditonal statement, something like:
if(works[work].assigneeMode == "ALL_STUDENTS" || (works[work].assigneeMode == "INDIVIDUAL_STUDENTS" && works[work].individualStudentsOptions.studentIds.indexOf(idStudent)!=-1))
{
var responseS = Classroom.Courses.CourseWork.StudentSubmissions.list(idCourse, idWork, optionalArgs2);
...
}

Formating date values for display in Can.js

All my dates come formatted as ISO 8601 from the backend, eg 2014-01-01T12:45:30Z. Across the application, I want to display them in different formats...
shorthand in tables, eg Jan 1
longer, more explicit format on a detailed view, eg Monday, January 1st.
Solution I made a helper where I can pass in the format. Easy enough.
can.mustache.registerHelper('formatDate', function(date, format) {
return date() ? moment(date()).format(format) : '-';
});
Problem Now I'm implementing the bootstrap datepicker, how can I capture these requirements...
the date in my model is formatted as ISO
bind to input with can-value in template
display format MM/DD/YY for users and datepicker
Bonus points if I don't need to make a compute for every single date value in my models, as they're quite large and with many dates.
Unfortunately there isn't a nice API for this(yet). However, you can achieve custom formats in a view while keeping your model properties pristine with the below code.
can.view.attr('can-somecustom-value', function(el, data) {
var attr = el.getAttribute('can-somecustom-value'),
value = data.scope.computeData(attr, {
args: []
}).compute;
new FormattedValue(el, {
value: value
//value is the only one we really care about, but
//you could specify other arbitrary options here
//such as "format: 'MM/DD/YYYY' to be used in your __format methods below"
});
});
var FormattedValue = can.Control.extend({
init: function () {
this.set();
},
__format: function() {
// return formatted version of this.options.value;
},
__deformat: function() {
// return this.element[0].value sans format(keeps your model pristine);
},
'{value} change': 'set',
set: function () {
if (!this.element) {
return;
}
var self = this;
setTimeout(function() {
self.element[0].value = self.__format();
});
},
'change': function () {
if (!this.element) {
return;
}
this.options.value(this.__deformat());
}
});
This will allow you to do the following:
<input can-somecustome-value="myDateProp"/>
where "myDateProp" is an attribute on some can.Map/can.Model/etc.
This will result in the input displaying a custom string format, while someModel.attr('myDateProp') will still return the ISO format(which in turn means the ISO format will also be saved to the server).
There is some internal discussion regarding adding filters/parsers to allow control over formats specific only to view rendering.

Colorize the CRM grid

How can I colorize the CRM grid on Dynamics CRM 4?
I would like to automatically display the list of an entity with a back color when loading the view.
My goal is to have different colors depending on the status of the listed entity. For example, I want to have a color for cases that have a date field that is in the past and another color for cases that have this date in the future.
The solution described below is a change not supported by Microsoft (that means, use it at your own risks). Plus, there is no guarantee that it won't be broken when applying CRM rollups.
On the CRM server, modify the C:\Program Files\Microsoft Dynamics CRM\CRMWeb\_static\_grid\grid.htc file:
Add the following code at the end of the initializeData() function:
if (window.location.href.toLowerCase() ==
"http://CrmServerName:5555/OrganizationName/cs/home_cases.aspx") {
// We ensure that we are on the organization we want to colorize and that we
// are on the Cases page
var colorizeColumn = InnerGrid.FindColumnIndex("new_date");
if (colorizeColumn > 0) {
// We ensure that the column we'll use to colorize is present
for (var i = 0; i < InnerGrid.AllRecords.length; i++) {
// For each line
// Build the date value from the displayed date
var new_date_displayed = InnerGrid.AllRecords[i][3].
cells[colorizeColumn].innerText;
var new_date_value = new Date(new_date_displayed.substring(6,10),
new_date_displayed.substring(3,5) - 1,
new_date_displayed.substring(0,2),
new_date_displayed.substring(11,13),
new_date_displayed.substring(14,16), 0, 0);
// Get current date
var current_datetime = new Date();
if (new_date_value <= current_datetime) {
InnerGrid.rows[i].style.backgroundColor="ff0066";
} else {
InnerGrid.rows[i].style.backgroundColor="ff6600";
}
}
}
}
And here's what you get:

Automated control of a Telerik RadDatePicker

I'm using WatIn to create an automated test for a Web App that uses Telerik controls: my first challenge is to drive a Telerik date control - a RadDatePicker.
Simply entering the text in the likeliest input field doesn't work: the value is reset to blank as the form is posted. So I imagine I need a more complex set of automated interactions -- for example, I found this thread on the Telerik site discussing how to automated a selection from a Telerik combo box.
Can anyone supply the magic combination of interactions I need?
(I'm sure that the answer would help anyone using any automated test tool, hence I've also flagged this question with a couple of other test frameworks too :-))
I'm using Selenium RC and had a similar problem few days ago. It took me ages to find the right way of doing it so I thought I will share the solution that worked for me:
(NOTE: I couldn't use $find)
The javascript to set the date on the RadDatePicker is:
var appBrowser = this.browserbot.getCurrentWindow();
var datepicker = appBrowser.yourDatePickerId; //note: no quotes
var selectDate=new Date();
selectDate.setFullYear(yourYear,yourMonth,yourDay);
datepicker.SetDate(selectDate);
datepicker.DateInput.SetDate(selectDate);
and then use selenium GetEval in your test to call javascript code to set the date:
selenium.GetEval("javascript here");
You should definitely wrap it around some parametrised helper class that will generate the javascript code for you each time you want to set the date in the test by passing id of the control and date.
I finally have a solution that works. The key is to use javascript to call the client-side API for the telerik control. The same technique is required for all complex Telerik controls, e.g. RadInput.
I used the technique recommended on the WatiN website for writing your own control http://watinandmore.blogspot.com/2009/12/wrapping-complex-logic-in-control.html to come up with this:
public class TelerikDatePicker : Control<TextField>
{
public DateTime? Value
{
get
{
var jScript = string.Format(#"$find(""{0}"").get_selectedDate();", Element.Id);
var selectedDateStr = Eval(jScript);
return TranslateJavascriptDateStringIntoDateTime(selectedDateStr);
}
set
{
var jScript = string.Format(#"$find(""{0}"").set_selectedDate(new Date(""{1:MMMM dd,yyyy}""));", Element.Id, value);
Eval(jScript);
}
}
public void SetValue(DateTime? value)
{
if (value.HasValue)
Value = value.Value;
else
Clear();
}
public void Clear()
{
var jScript = string.Format(#"$find(""{0}"").clear();", Element.Id);
Eval(jScript);
}
private string Eval(string script)
{
return Element.DomContainer.Eval(script);
}
public bool IsEnabled()
{
var jScript = string.Format(#"$find(""{0}"").get_enabled();", Element.Id);
return Eval(jScript) == "true";
}
private DateTime? TranslateJavascriptDateStringIntoDateTime(string jsDateStr /*E.g. Mon Mar 12 00:00:00 UTC+0100 2012*/)
{
if (String.IsNullOrEmpty(jsDateStr) || jsDateStr == "null") return null;
var abbreviatedMonth = jsDateStr.Substring(4, 3);
var dayOfTheMonth = jsDateStr.Substring(8, 2).TrimEnd(' ');
var year = jsDateStr.Substring(jsDateStr.Length-4, 4);
const string format = "d MMM yyyy";
var dateStr = dayOfTheMonth + " " + abbreviatedMonth + " " + year;
return DateTime.ParseExact(dateStr, format, CultureInfo.InvariantCulture);
}
}
I had the same issue with a RadDatePicker that would post back empty after typing in values.
I managed to automate typing in the date into the input field with these steps:
Select the dateInput text box associated with the control.
Do a dateInput.MouseClick() on it
Type the date into the field Manager.Desktop.KeyBoard.TypeText("1/1/1990")
Do a .MouseClick() on any other element on the page, e.g. some div
I found that #4 was needed to fire the events to make the control blur therefore "saving" its value.
Then you can submit and the value should go along with it.
Solved that problem for SeleniumIDE - you have to use "fireEvent" method with value "blur" for "ControlID" after you've set value using "sendKeys" or "type" methods. Strange that this problem does not occur when automating with WebDriver.

Resources