I am trying to display details of a SharePoint document library using knockout.js.I want the name of the item or the URL to be clickable.Is it possible? I am trying below code but it is not formatting to URL link <a hrefr=# data-bind="attr: {href: Designation}, text:Designation"></a>
Below is the source code
<table id="tblEmployeeList" border="1">
<thead>
<tr>
<th>Name</th>
<th>Designation</th>
<th>Department</th>
<th>Location</th>
</tr>
</thead>
<!-- Iterating through every list item using foreach of KO -->
<tbody data-bind="foreach: Employees">
<tr>
<td data-bind="text: Name"></td>
**<td </td>**
<td data-bind="text: Department"></td>
<td data-bind="text: Location"></td>
</tr>
</tbody>
</table>
Javascript
ExecuteOrDelayUntilScriptLoaded(MainFunction, "sp.js");
var completeEmployeeList = null;
// Class used for saving the field values.
function EmployeeList(name, designation, department, location) {
var self = this;
self.Name = name;
self.Designation = designation;
self.Department = department;
self.Location = location;
}
// View Model - JavaScript that defines the data and behavior of your UI
function EmployeeListViewModel() {
var self = this;
// observableArray equivalent of a regular array,
self.Employees = ko.observableArray([]);
self.AddEmployees = function (name, designation, department, location) {
self.Employees.push(new EmployeeList(name, designation, department, location));
}
}
function MainFunction() {
completeEmployeeList = new EmployeeListViewModel();
// Retrieve the SharePoint list items
retrieveListItems();
// Activates knockout.js
ko.applyBindings(completeEmployeeList);
}
function retrieveListItems() {
var clientContext = new SP.ClientContext.get_current();
var oList = clientContext.get_web().get_lists().getByTitle('Documents');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><RowLimit>10</RowLimit></View>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(sender, args) {
var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var currentItem = listItemEnumerator.get_current();
completeEmployeeList.AddEmployees(currentItem.get_item("Title"), currentItem.get_item("FileRef"), currentItem.get_item("Editor"),currentItem.get_item("File_x0020_Size"), currentItem.get_item("Modified"));
}
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
This seems to work as I'd expect. If you aren't seeing a clickable link maybe there's something in your css changing the styling?
Here's a repro snippet, but I removed code related to your api calls:
var completeEmployeeList = null;
// Class used for saving the field values.
function EmployeeList(name, designation, department, location) {
var self = this;
self.Name = name;
self.Designation = designation;
self.Department = department;
self.Location = location;
}
// View Model - JavaScript that defines the data and behavior of your UI
function EmployeeListViewModel() {
var self = this;
// observableArray equivalent of a regular array,
self.Employees = ko.observableArray([]);
self.AddEmployees = function(name, designation, department, location) {
self.Employees.push(new EmployeeList(name, designation, department, location));
}
}
function MainFunction() {
completeEmployeeList = new EmployeeListViewModel();
// Retrieve the SharePoint list items
//retrieveListItems();
//test value
completeEmployeeList.AddEmployees('Test Name', 'Test Dept', 'Test Designation', 'Test Location');
// Activates knockout.js
ko.applyBindings(completeEmployeeList);
}
MainFunction()
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tblEmployeeList" border="1">
<thead>
<tr>
<th>Name</th>
<th>Designation</th>
<th>Department</th>
<th>Location</th>
</tr>
</thead>
<!-- Iterating through every list item using foreach of KO -->
<tbody data-bind="foreach: Employees">
<tr>
<td data-bind="text: Name">
<span data-bind="text: Name"></span>
</td>
<td>
</td>
<td data-bind="text: Department"></td>
<td data-bind="text: Location"></td>
</tr>
</tbody>
</table>
Related
I want to be able to upload a file then to download it or delete it. But when I try to delete it, I get this error:
The view 'Delete' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/FileUpload/Delete.aspx ,~/Views/FileUpload/Delete.ascx, ~/Views/Shared/Delete.aspx,~/Views/Shared/Delete.ascx, ~/Views/FileUpload/Delete.cshtml, ~/Views/FileUpload/Delete.vbhtml, ~/Views/Shared/Delete.cshtml ,~/Views/Shared/Delete.vbhtml .
[HttpGet]
public ActionResult Delete( string deletedfile)
{
string current_usr = User.Identity.GetUserId();
string fullPath = Request.MapPath("~/Files/" + current_usr + "/" + deletedfile);
if (System.IO.File.Exists(fullPath))
{
System.IO.File.Delete(fullPath);
ViewBag.Message="Deleted";
}
var items = GetFiles();
return View(items);
}
// GET: FileUpload
public ActionResult Index()
{
var items = GetFiles();
return View(items);
}
// POST: FileUpload
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
try
{
string current_usr = User.Identity.GetUserId();
//string path = Path.Combine(Server.MapPath("~/Files/"),
// Path.GetFileName(file.FileName));
var folder = Server.MapPath("~/Files/" + current_usr + "/");
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
string path = Path.Combine(String.Format(folder),
Path.GetFileName(file.FileName));
file.SaveAs(path);
ViewBag.Message = "File uploaded successfully";
}
catch (Exception ex)
{
ViewBag.Message = "ERROR:" + ex.Message.ToString();
}
else
{
ViewBag.Message = "You have not specified a file.";
}
var items = GetFiles();
return View(items);
}
public FileResult Download(string downloadedfile)
{
string current_usr = User.Identity.GetUserId();
var FileVirtualPath = "~/Files/" + current_usr + "/" + downloadedfile;
return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
private List<string> GetFiles()
{
string current_usr = User.Identity.GetUserId();
var dir = new System.IO.DirectoryInfo(Server.MapPath("~/Files/" + current_usr + "/"));
System.IO.FileInfo[] fileNames = dir.GetFiles("*.*");
List<string> items = new List<string>();
foreach (var file in fileNames)
{
items.Add(file.Name);
}
return items;
}
The View :
<h2> File Upload </h2>
#model List<string>
#using (Html.BeginForm("Index", "FileUpload", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<label for="file"> Upload </label>
<input type="file" name="file" id="file" />
<br /><br />
<input type="submit" value="Upload" />
<br /><br />
#ViewBag.Message
<br />
<h2>Documents list</h2>
<table style="width:100%">
<tr>
<th> File Name </th>
<th> Link </th>
</tr>
#for (var i = 0; i <= (Model.Count) - 1; i++)
{
<tr>
<td>#Model[i].ToString() </td>
<td>#Html.ActionLink("Download", "Download", new { downloadedfile = Model[i].ToString() }) </td>
<td>
#Html.ActionLink("Delete", "Delete", new { deletedfile = Model[i].ToString() })
</td>
</tr>
}
</table>
}
The issue is that your Delete Controller method is calling View() at the end. That method will attempt to find a view file with the name of the controller method. If you want to show the list of files after the delete you can redirect to your index action like this:
[HttpGet]
public ActionResult Delete(string deletedfile)
{
string current_usr = User.Identity.GetUserId();
string fullPath = Request.MapPath("~/Files/" + current_usr + "/" + deletedfile);
if (System.IO.File.Exists(fullPath))
{
System.IO.File.Delete(fullPath);
ViewBag.Message = "Deleted";
}
return RedirectToAction("Index");
}
See this link from the microsoft Docs for more detail on redirecting
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/views/asp-net-mvc-views-overview-cs
I am trying to multiply two different data fetched from the database and have the result displayed on a table. I am having issues multiplying data from two different rows and displaying the result on same table.
// code to filter and render table
renderTable() {
var totalCount = 0;
var shownCount = 0;
var lowerBound = 0;
var upperBound = 0;
var filtered = [];
filtered = this.state.data.map( (row, i,) => {
if(row.department.toLowerCase().indexOf(this.state.departmentFilter) > -1){
return (
<tr key={"employeeData"+i}>
<td>{i+1}</td>
<td>{row.name}</td>
<td>{row.numberofPresentAttendances}</td>
<td>{row.department}</td>
<td>{row.wages}</td>
<td>{row.totalWages}</td>
<td>
</td>
</tr>
);
} else {
return undefined;
}
});
<table className="employee-table">
<tbody>
<tr>
<th>No</th>
<th>Name</th>
<th>Attendance in the last 7days</th>
<th>Department</th>
<th>Wage/hr</th>
<th>Total Wages</th>
<th></th>
</tr>
{ filtered }
</tbody>
</table>
// mongoose models
var employeeSchema = mongoose.Schema({
name: String,
department: String,
wages:Number,
attendances: Object
},{timestamps:true});
var Employee = mongoose.model('Employee', employeeSchema);
I would like to multiply the Wages/hr and numberofPresentAttendances in the frontend
I am not sure if I understand your question completely but if you want to show the result of (numberofPresentAttendances * wages) then you can do something like this:
filtered = this.state.data.map( (row, i,) => {
if(row.department.toLowerCase().indexOf(this.state.departmentFilter) === -1){
return null;
}
return (
<tr key={"employeeData"+i}>
<td>{i + 1}</td>
<td>{row.name}</td>
<td>{row.numberofPresentAttendances}</td>
<td>{row.department}</td>
<td>{row.wages}</td>
<td>{row.numberofPresentAttendances * row.wages}</td>
</tr>
);
});
Although I am not sure why you are using variable numberofPresentAttendances instead of attendances as mentioned in your mongoose schema.
#if (ViewData["post"] != null)
{
foreach (var item in ViewData["post"] as IEnumerable<Employee.Models.ApplyJob>)
{
<tr>
<td>#item.PerferenceNo</td>
<td>#item.JobName</td>
<td>#item.Location</td>
<td>Action</td>
</tr>
}
}
how to use row span on PerferenceNo and JobName using MVC4>
You need to compare the previous values with the current values, but there is no need to use rowspan (which would unnecessarily complicate it). You can just generate an empty <td> element when the cell matches the previous value.
#{
var data = ViewData["post"] as IEnumerable<Employee.Models.ApplyJob>;
int perferenceNo = 0;
string jobName = "";
}
#foreach (var item in data)
<tr>
#if (item.PerferenceNo == perferenceNo)
{
<td></td>
}
else
{
perferenceNo = item.PerferenceNo;
<td>#item.PerferenceNo</td>
}
... // ditto for JobName
<td>#item.Location</td>
</tr>
}
And I strongly recommend you pass a model to the view, rather than casting it from ViewData
If you do want to use the rowspan attribute, then you code will need to be
#foreach (var item in items)
{
int perferenceNoCount = data.Count(x => x.PerferenceNo == item.PerferenceNo);
int jobNameCount = data.Count(x => x.JobName == item.JobName);
<tr>
#if (item.PerferenceNo != perferenceNo)
{
perferenceNo = item.PerferenceNo;
<td rowspan="#(perferenceNoCount)">#item.ID</td>
}
#if (item.JobName != jobName)
{
jobName = item.JobName;
<td rowspan="#(jobNameCount)">#item.Name</td>
}
<td>#item.Location</td>
</tr>
}
But you really should be using view model in that case with properties for the rowspan values and run your queries in the controller.
I created test Spring Boot + AngularJS app to test checkboxes:
html:
... <thead>
<tr>
<th><input type="checkbox" ng-model="isAllSelected"
ng-click="selectAll()"></th>
<th>Lp.</th>
<th>ID</th>
<th>Name</th>
<th>Parent Id</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="test in tests">
<td><input type="checkbox" ng-model="test.checked"
ng-change="optionSelected()" /></td>
<td>{{$index+1}}.</td>
<td>{{test.id}}</td>
<td>{{test.name}}</td>
<td>{{test.parentId}}...
test_controller.js:
(function(angular) {
var AppTestController = function($scope, Test) {
var vm = this;
vm.tests = [];
vm.loadAll = loadAll;
loadAll();
function loadAll() {
Test.query(function(result) {
vm.tests = result;
});
}
vm.selectAll = function() {
var toggleStatus = vm.isAllSelected;
angular.forEach(vm.tests, function(itm) {
itm.checked = toggleStatus;
});
}
vm.optionSelected = function() {
vm.isAllSelected = vm.tests
.every(function(itm) {
return itm.checked;
})
}
};
AppTestController.$inject = [ '$scope', 'Test' ];
angular.module("myApp.test_controller").controller(
"AppTestController", AppTestController);
}(angular));
This works for me as spring Boot app, but when I do the same in JHipster it doesn't work.
How can I get it to work in JHipster?
This is what I currently used and it works!:
.html
<thead>
<tr jh-sort="vm.predicate" ascending="vm.reverse" callback="vm.transition()">
<!--th jh-sort-by="id"><span data-translate="global.field.id">ID</span> <span class="glyphicon glyphicon-sort"></span></th-->
<th><input type="checkbox" icheck ng-change="vm.selectAll()" ng-model="vm.checkAll[vm.page]"></th>
<th jh-sort-by="id"><span data-translate="global.field.id">ID</span></th>
---
</tr>
</thead>
<tbody>
<tr ng-repeat="school in vm.schools track by school.id">
<td><input type="checkbox" icheck ng-model="vm.checkboxes[school.id]" ng-change="vm.select(school)"/></td>
<td>{{($index + 1) + (vm.page - 1) * vm.itemsPerPage}}</td>
...
</tr>
</tbody>
.js
vm.checkAll = [];
var map = {};
vm.checkboxes = [];
vm.selectedItems = [];
vm.selectAll = selectAll;
vm.select = select;
function selectAll () {
var value = vm.checkAll[vm.page];
angular.forEach(vm.schools, function(item) {
if (angular.isDefined(item.id)) {
if(vm.checkboxes[item.id] != value) {
vm.checkboxes[item.id] = value;
vm.select(item);
}
}
});
};
function select (item) {
var value = vm.checkboxes[item.id];
if(value) {
vm.selectedItems.push(item);
if(map[vm.page] == null) map[vm.page] = 1;
else map[vm.page] = map[vm.page] + 1;
if(map[vm.page] == vm.schools.length) {
vm.checkAll[vm.page] = true;
}
} else {
vm.selectedItems.splice(item, 1);
if(map[vm.page] == null) map[vm.page] = 0;
else map[vm.page] = map[vm.page] - 1;
if(map[vm.page] < vm.schools.length) {
vm.checkAll[vm.page] = false;
}
}
};
I want to write an asynchronous Controller that is displaying in output an IEnumerable<IEnumerable<Video>>
I don't know I can manage to write correctly my function Task<IEnumerable<IEnumerable<Video>>> GetVideosAsync(xxxxx) especially the Task.ContinueWhenAll function (in order not to have blocking code ).
Is it better to use a lambda for this piece of code ...?
Can someone help me ?
Nb: *I can only use C#4 and visual Studio 2010
public class HomeController : AsyncController
{
string[] sources = {
"http://xxxx/membervideos/1",
"http://xxxx/membervideos/2"
};
public Task<ActionResult> Async()
{
var sw = Stopwatch.StartNew();
var data = GetVideosAsync();
sw.Stop();
ViewBag.Elapsed = sw.ElapsedMilliseconds;
return View("~/views/home/index.cshtml", data);
}
Task<IEnumerable<IEnumerable<Video>>> GetVideosAsync()
{
var allVideosTasks = new List<Task<IEnumerable<Video>>>();
foreach (var url in sources)
{
allVideosTasks.Add(DownloadDataAsync(url));
}
var context = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.ContinueWhenAll<IEnumerable<Video>,IEnumerable<IEnumerable<Video>>(
/// CODE TO ComplETE HERE
);
Task<IEnumerable<Video>> DownloadDataAsync(string url)
{
var httpClient = new HttpClient();
var httpResponseMessage = httpClient.GetAsync(url);
var result = httpResponseMessage.ContinueWith
(t =>
{
t.Result.EnsureSuccessStatusCode();
return t.Result.Content.ReadAsAsync<IEnumerable<Video>>();
}
).Unwrap();
return result;
}
/**** VIEW ******/
#{
ViewBag.Title = "Home Page";
}
#model IEnumerable<IEnumerable<MvcApplication1.Models.Video>>
<table>
#foreach (var memberVideos in Model)
{
<tr>
#foreach(var video in memberVideos){
<td>
<div>#video.Title</div>
<div><img src="http://xxxxxx/membervideos/#video.ImageUrl" style="width: 185px;"/> </div>
</td>
}
</tr>
}
</table>
<h1>#ViewBag.Elapsed</h1>