I am trying to use a AngularJS daterange picker to filter data based on a date range. I cannot figure out why I am getting the TypeError "Cannot read property 'startDate' of undefined. Near the top of the angularjs controller I'm defining the date object with the startDate property. But I still get this error. Is this an issue with SharePoint? How do can I fix this to work in SharePoint. The code works fine in a LAMP stack with a local json file but not on SP. I attempting to run on SP 2016. Thank you.
Here is how I am bringing in all the dependencies in the head of the html file.
<head>
<title>Rolling Log</title>
<meta charset="uft-8">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/daterangepicker.css" />
<link rel="stylesheet" href="css/styles.css">
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/angular.js"></script>
<!-- <script src="js/angular-route.js"></script> -->
<script src="js/moment.js"></script>
<script src="js/daterangepicker.js"></script>
<script src="js/angular-daterangepicker.js"></script>
</head>
This the body of the html file:
<body ng-app="myApp" ng-controller="myController" ng-clock>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
...
</nav>
<div class="wrapper">
<div><h1>CM Rolling Log</h1></div>
<div id="top">
<hr>
<span style="float: right; padding: 2px;">Search: <input type="text" ng-model="searchText"></span>
<label class="my-auto mr-2">Date Opened:</label>
<input date-range-picker class="form-control" ng-model="datePicker.date" clearable="true" style="max-width: 280px;">
<table>
<tr>
<th ng-click="sortBy('timestamp')" width="10%">Date Time</th>
<th ng-click="sortBy('Action')" width="70%">Action</th>
<th ng-click="sortBy('AO')" width="15%">AO</th>
</tr>
<tr ng-repeat="item in log | orderBy:sortField:reverseOrder | filter:searchText | myfilter: datePicker.date">
<td>{{item.timestamp | date: 'MM/dd/yyyy HH:MM'}}</td>
<td>{{item.Action | removeHTMLTags | strip }}</td>
<td>{{item.AO}}</td>
</tr>
</table>
</div>
<div id="bottom">
<form action="" method="POST" ng-submit="createFunc()">
<br /><span id="user"></span> <br /> <br />
Comment: <br /> <textarea id="action" rows="5" cols="130" name="comment"></textarea> <br /><br />
<input type="submit" name="submit_btn" value="Post comment">
</form>
</div>
</div>
The angularjs code with the applied date range picker is at bottom.
var app = angular.module('myApp', ['daterangepicker']);
app.filter('removeHTMLTags', function() {
return function(text) {
return text ? String(text).replace(/<[^>]+/gm, '') : '';
}
});
app.controller('myController',
function($scope, $http) {
$http({
method: 'GET',
url: "https://.../_api/web/lists/GetByTitle('RollingLog')/items?$top=1000&$select=timestamp,Action,AO",
headers: {"Accept": "application/json;odata=verbose"}
}).then(function (data, status, headers, config) {
$scope.log = data.data.d.results;
$scope.datePicker = { date: {
startDate: null, endDate: null
} };
$scope.searchText = "";
$scope.reverseOrder = true;
$scope.sortField = "timestamp";
$scope.sortBy = function(sortField) {
$scope.reverseOrder = ($scope.sortField === sortField) ? !$scope.reverseOrder : false;
$scope.sortField = sortField;
};
jQuery.ajax({
url: "https://.../_api/web/currentuser?$select=Title",
type: "GET",
headers: {"Accept": "application/json;odata=verbose","Content-Type": "application/json;odata=verbose"},
success: function(data) {
username = data.d.Title;
console.log("user name: " + username);
document.getElementById("user").innerHTML = username;
},
error: function(data) {
console.log("Error occurred trying to get user id");
}
});
}, function errorCallback(response) {
});
$scope.getFormDigest = function() {
console.log("Inside getFormDigest");
var formdigest;
jQuery.ajax({
url: "https://.../_api/contextinfo",
type: "POST",
async: false,
headers: {
"accept": "application/json;odata=verbose",
type: "POST"
},
success: function(data)
{
console.log(typeof data);
formdigest = data.d.GetContextWebInformation.FormDigestValue
}
});
return formdigest;
};
$scope.createFunc = function() {
console.log("Inside createFunc...");
var dt = new Date();
var action = document.getElementById("action").value;
var formdigest = $scope.getFormDigest();
jQuery.ajax({
url: "https://.../_api/web/lists/GetByTitle('RollingLog')/items",
method: "POST",
data: JSON.stringify({
'__metadata' : {'type': 'SP.Data.RollingLogListItem'},
'Action': action,
'AO': username,
'timestamp': dt
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": formdigest
},
success: function(data) {
console.log("entry created successfully...");
},
error: function(data) {
console.log(("#__REQUESTDIGEST").val());
console.log("Error message: " + JSON.stringify(data.responseJSON.error));
}
});
};
}
).filter('strip', function() {
return function(str) {
return str.replace(/>/g, '').replace(/ /g, ' ').replace(/>/g, '').replace(/>>/g, '').replace(/;/g, '').replace(/#/g, '"').replace(/"/g,'"');
}
});
app.filter("myfilter", function() {
return function(items, date) {
if (!date.startDate || !date.endDate) {
return items
}
startDate = moment(date.startDate);
endDate = moment(date.endDate);
return items.filter(function(elem) {
var openedDate = moment(elem.date_opened);
return startDate.diff(openedDate, 'days') <= 0 && endDate.diff(openedDate, 'days') >= 0;
});
};
});
You are initializing your datepicker when your promise is resolved (inside "then"), therefore before then your datepicker is undefined and because of this you are getting "Cannot read property 'startDate' of undefined" error. You can
1) move your initialization code to the begining of the controller
app.controller('myController',
function($scope, $http) {
$scope.datePicker = { date: {
startDate: null, endDate: null
} };
...
2) or you can add null control inside your filter
app.filter("myfilter", function() {
return function(items, date) {
if(date == undefined){
return items;
}
if (!date.startDate || !date.endDate) {
return items
}
startDate = moment(date.startDate);
endDate = moment(date.endDate);
return items.filter(function(elem) {
var openedDate = moment(elem.date_opened);
return startDate.diff(openedDate, 'days') <= 0 && endDate.diff(openedDate, 'days') >= 0;
});
};
});
To get rid of such errors I would use ng-if
to promise that the filter receives datePicker
with date
.
I believe you don't want to show the table rows ae to call ng-repeat
till datePicker.date
is initialized.
<tr ng-if="datePicker && datePicker.date"
ng-repeat="item in log | orderBy:sortField:reverseOrder | filter:searchText | myfilter: datePicker.date">
</tr>
In this case, myfilter
will be called once datePicker.date
is not undefined
and it is already synced with the digest cycle so you don't need additional watchers.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.