Knockout: model function not firing - knockout-2.0

Knockout model function not firing on click event
Hi Friends,
I have following html code that has the model binded to the div element "bindingDiv" :
<div class="clear" id="bindingDiv">
<div class="col-sm-8">
<table class="table table-bordered table-hover" data-bind="visible: Documents().length > 0">
<thead>
<tr>
<th class="col-md-2">
Name
</th>
<th>
Display Name
</th>
<th style="max-width: .5% !important; min-width: .5% !important; text-align: center;
width: .5% !important;">
</th>
</tr>
</thead>
<tbody data-bind="foreach: Documents">
<tr>
<td>
<span data-bind="text: Id, visible:false"></span>
<span data-bind="text: Name"></span>
</td>
<td>
<span data-bind="text: DisplayName"></span>
</td>
<td>
<img class="action" title="Tools" data-placement="right" data-toggle="popover" src="~/Content/images/tool.png"
alt="tool" />
<div class="actions" style="display: none;">
<ul class="action-links" style="min-width: 75px;">
<li><a class="tool tool-remove" data-bind="click: $root.deleteDocument">Delete</a></li>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
The following is the model object:
function Document(data) {
var self = this;
self.Id = ko.observable(data.Id);
self.Name = ko.observable(data.Document.Name);
self.DisplayName = ko.observable(data.Document.DisplayName);
self.Description = ko.observable(data.Document.Description);
self.DocumentPath = ko.observable(data.Document.DocumentPath);
self.DocumentTypeId = ko.observable(data.Document.DocumentTypeId);
};
var isBindingComplete = true;
function CourseDocumentModel(docs) {
var self = this;
self.Documents = ko.observableArray(ko.utils.arrayMap(docs, function (doc) { var d = new Document(doc); return d; }));
self.addDocument = function (doc) {
var document = new Document(doc);
self.Documents.push(document);
};
self.reloadDocuments = function(docs) {
self.Documents.removeAll();
ko.utils.arrayMap(docs, function (doc) { self.Documents.push(new Document(doc)) });
};
self.deleteDocument = function(doc) {
if (!isBindingComplete) {
return;
}
alert(ko.toJSON(doc));
var conf = true;
conf = confirm("Are you sure you want to delete?");
if (conf) {
$.ajax({
type: "POST",
url: "#Url.Action("DeleteDocument", Controllers.Course)/",
data: ko.toJSON(doc),
contentType: 'application/json',
success: function (mydata) {
self.Documents.remove(doc);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("removeDocument method error status: " + xhr.status);
alert("removeDocument method error thrown: " + thrownError);
}
});
}
};
};
$(document).ready(function() {
refreshGrid(null);
});
var model;
function refreshGrid(uploadRow)
{
isBindingComplete = false;
$.ajax({
url: "#Url.Action("GetAllDocuments", Controllers.Course)/",
type: "get",
contentType: "application/json",
success: function (docs) {
if(model == null)
{
model = new CourseDocumentModel(docs);
ko.applyBindings(model, document.getElementById("bindingDiv"));
}
else
{
model.reloadDocuments(docs);
}
if(uploadRow != null)
$(uploadRow).fadeOut();
refreshPopover();
isBindingComplete = true;
},
error: function (xhr, ajaxOptions, thrownError) {
//alert("refreshGrid error status: " + xhr.status);
//alert("refreshGrid error thrown: " + thrownError);
isBindingComplete = true;
}
});
}
I'm facing two issues here:
The deleteDocument method defined in the model CourseDocumentModel is automatically fired for the number of documents binded. I 'm not sure how this event is triggered when the ko.applyBindings(model, document.getElementById("bindingDiv")) is executed from the regreshGrid method. So as a workaround I have used a flag to determine if the binding is completed or not
After binding, If I click the Delete button from the html code, the model function deleteDocument is not firing. I don't see any issues in the console (Firebug). I googled and found suggestion of $root.deleteDocument($data) but still the issue remains. Can you please guide me addressing the issue?
Thanks,
Hemant.

Related

Nodejs Wait for all promises to resolve and then redirect

I am facing the problem in redirecting to index page. Instead page refreshes to same create page perhaps due to large size images are still copying but why page refreshing instead of images waiting copying to finish and then redirecting.
module.exports.create_customModel_post = async (req, res) => {
const {images} = req.files
let myPromise = []
if (images) {
const dir = `./public/${req.body.slug}`
fs.mkdirSync(dir, { recursive: true });
for (let i = 0; i < images.length; i++) {
const uploadTo = `${dir}/${images[i].name}`
myPromise.push(new Promise(function(resolve, reject) {
images[i].mv(uploadTo, (err) => {
if(err){
reject(err);
}else{
resolve(uploadTo);
}
});
}));
}
}
Promise.all(myPromise).then(function(values) {
console.log(values),
// THIS REDIRECT IS NOT WORKING
res.redirect('/admin/custom-models')
}).catch(function (reasons) {
console.log(reasons);
});
}
Response from server
POST /admin/create-custom-model - - ms - -
new model is created & saved
[
'./public/testing/attachment_48549925.svg',
'./public/testing/brand-name.png',
'./public/testing/design.svg',
'./public/testing/model-name.png',
'./public/testing/path9080.png',
]
GET /admin/create-custom-model 200 12.375 ms - -
here is form I am using. Removed extra
<main>
<section class="">
<div class="container">
<h1>Create Custom Model</h1>
<table class="">
<form enctype="multipart/form-data" method="post">
<tr>
<td></td>
<td>
<input type="file" name="images" multiple>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td>Cancel </td>
<td><button type="submit" >Save</button></td>
</tr>
</form>
</table>
</div>
</section>
</main>

NodeJS template literal with async map

I'm trying to generate an HTML content using template literal because I need to loop through an array. It is not returning the map content to the template literal.
const htmlData = `
<html>
... // Some content here
<table class="table table-bordered" style="width: 800px;" align="center">
<thead class="thead-light">
<tr>
<th>Company</th>
<th>Bill Date</th>
<th>Billing Days</th>
<th>Total Units</th>
</tr>
</thead>
<tbody>
${customers.map( async (customer) => {
let units = 0;
const companyDate = new Date(customer.CompanyStartDate);
const billDate = new Date(today.getFullYear(), today.getMonth(), companyDate.getDate());
const numDays = (today.getTime() - billDate.getTime()) / (1000 * 3600 * 24);
const pData = await property.getPropTotalUnitsByCompany(customer.CompanyID);
return (
`
<tr>
<td>
${pData.map(async (propData) => {
units += propData.TotalUnits;
return (
`
<div class="row">
<div class="col-sm-12" align="right">
Property: ${propData.PropertyName} Total Units: ${propData.TotalUnits}
</div>
</div>
`
);
})}
</td>
<td>${myFunctions.formatDisplayDate(billDate)}</td>
<td>${numDays}</td>
<td>${units}</td>
</tr>
`
);
})}
</tbody>
</table>
... // More content here
</html>
`;
It returns [object Promise] inside my . Here is where I have the .map(). Can't I use map in template literals?
Thank you

Ajax in JavaScript is posting raw data into web page

When making an ajax request in JavaScript, it appears that the view has received a post of raw data into web page, i would say this is like looking at a csv file in notepad, just lines and lines of data, albeit the correct data, just not in the jquery datatable i would expect to see.
When just using Jquery to display all the data correctly in the table like so:
<script>
$('#IndexTable').DataTable({ responsive: true });
</script>
There is no issue.
I have also tried this in the view:
<script>
$(document).ready(function () {
test();
})
var test = function () {
$ajax({
type: 'GET',
url: '/ClinicalASSPATVM/test',
success: function (response) {
BindDataTable(response);
}
})
}
var BindDataTable = function (response) {
$("#IndexTable").DataTable({
"aadata": response,
"aoColumn": [
{"mData": "Product:"},
]
});
}
</script>
This is my Controller portion of the code:
public ActionResult test(int? ClinicalAssetID)
{
var ClinicalASSPATVM = (from s in db.ClinicalAssets
join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
from subpat in AP.DefaultIfEmpty()
orderby s.ClinicalAssetID descending
select new ClinicalASSPATVM
{
ClinicalAssetID = s.ClinicalAssetID,
ProductName = s.ProductName,
ModelName = s.ModelName,
SupplierName = s.SupplierName,
ManufacturerName = s.ManufacturerName,
SerialNo = s.SerialNo,
PurchaseDate = s.PurchaseDate,
PoNo = s.PoNo,
Costing = s.Costing,
TeamName = s.TeamName,
StaffName = s.StaffName,
InspectionDocumnets = subpat.InspectionDocumnets ?? String.Empty,
InspectionOutcomeResult = subpat.InspectionOutcomeResult
});
return Json(new { data = ClinicalASSPATVM }, JsonRequestBehavior.AllowGet);
}
This is the View:
#model IEnumerable<Assets.Areas.Clinical.Models.ClinicalASSPATVM>
<link href="~/content/datatables/media/css/datatables.bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/DataTables/extensions/Responsive/css/responsive.dataTables.min.css" rel="stylesheet" />
#{
ViewBag.Title = "View Clinical";
}
<div class="pageheader">
<h2><i class="fa fa-pencil"></i> Clinical Asset Dashboard</h2>
<div class="breadcrumb-wrapper">
<span class="label">You are here:</span>
<ol class="breadcrumb">
<li>Asset Management System</li>
<li class="active">Clinical Assets - Overview</li>
</ol>
</div>
</div>
<div class="contentpanel">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-btns">
−
</div><!-- panel-btns -->
<h3 class="panel-title">Last 10 Assets:</h3>
</div>
<div class="panel-body">
<div class="table-responsive">
<table id="IndexTable" class="table table-striped table-bordered" >
<thead>
<tr>
<th>Product:</th>
<th>Model:</th>
<th>Supplier:</th>
<th>Manufacturer:</th>
<th>Serial No:</th>
<th>Purchase Date:</th>
<th>Purchase Order No:</th>
<th>Cost:</th>
<th>Team Location:</th>
<th>Owner:</th>
<th>Inspection OutcomeResult:</th>
</tr>
</thead>
</table>
</div><!-- table-responsive -->
</div><!-- panel-body -->
</div><!-- panel -->
</div>
#section Scripts {
<script src="~/Scripts/DataTables/media/js/jquery.dataTables.min.js"></script>
<script src="~/Scripts/DataTables/media/js/dataTables.bootstrap.min.js"></script>
<script src="~/Scripts/DataTables/extensions/Responsive/js/dataTables.responsive.js"></script>
<script>
$(document).ready(function () {
$ajax({
url: '/ClinicalASSPATVM/test',
method: 'GET',
datatype: 'json',
sucess: function (data) {
$('#IndexTable').datatable({
data: data,
columns: [
{ "data": "ProductName" },
]
});
}
});
});
</script>
}
This is the crazy output example, also i see no layout page headers, footers or side bars.
{"data":
[{"ClinicalAssetID":75,"SerialNo":"34563463453453453","PurchaseDate":"\/Date(1551657600000)\/","PoNo":"567","Costing":1500,"InspectionDocumnets":"","ProductName":{"ProductID":2,"AssetAssignmentID":2,"ProductName":"Bed"},"InspectionOutcomeResult":null,"ModelName":{"ModelID":1,"AssetAssignmentID":2,"ProductID":8,"ModelName":"M1"},"Code":null,"AssetTypeName":null,"ManufacturerName":{"ManufacturerID":1,"AssetAssignmentID":2,"ProductID":8,"ManufacturerName":"Omron"},"StaffName":{"StaffID":1,"StaffName":
I Hope someone can shed some light on what i have done wrong.

Loading a Partial view which has a complex model of many sub models into a jquery ui tab

I get an error when loading a particular view via an Html.action call to an action and Controller, into a jquery Tab.
The other View is loaded successfully via an HTML.Partial call.
How do I get this other particular partial loaded please.
The tab where the error happens is tab4.
The commented out HTML.Partial call works to a point but when it loads that Partial (User), which has multiple models in it's containing model,..those other models are null and it's iteration over them crashes.
(That partial is beneath the first block of code.)
If I try load it from an action Call, then
the JQuery function ("$#tabs").tabs crashes with ".tabs" is undefined
TIA
Code:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Tabs - Content via Ajax</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function ()
{
$("#tabs").tabs({
beforeLoad: function (event, ui)
{
ui.jqXHR.fail(function ()
{
ui.panel.html(
"Couldn't load this tab. We'll try to fix this as soon as possible. " +
"If this wouldn't be a demo.");
});
}
});
});
</script>
<div id="tabs">
<ul>
<li>Person Detail</li>
<li>Addresses</li>
<li>Role Detail</li>
<li>User Detail</li>
</ul>
<div id="tabs-1">
#*#Html.Partial("~/Views/Person/Index.cshtml")*#
</div>
<div id="tabs-2">
#*#Html.Partial("~/Views/Address/Index.cshtml")*#
</div>
<div id="tabs-3">
#Html.Partial("~/Views/IdentityRole/List.cshtml", new List<Catalyst.Shared.IdentityRole>())
</div>
<div id="tabs-4">
#Html.Action("List", "User");
#*#Html.Partial("~/Views/User/List.cshtml", new Catalyst.Mvc.IdentityUserPersonViewModel())*#
</div>
</div>
The Partial which I want to load, but needs data, which I think would work if I called the Action as opposed to calling the Partial.
#model Catalyst.Mvc.IdentityUserPersonViewModel
#{
ViewBag.User = "List";
}
<div class="panel panel-default" style="width:1400px !important;text-align:center ">
<div class="panel-heading">
<h3>Users</h3>
</div>
<div class="panel-body">
<div style="text-align:right;">#Html.ActionLink("Add", "Create", null, new { #class = "btn btn-default" })</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>
UserName
</th>
<th>
Password
</th>
<th>
Title
#*#Html.DisplayNameFor(model => model.)*#
</th>
<th>
FirstName
#*#Html.DisplayNameFor(model => model.)*#
</th>
<th>
LastName
</th>
<th>
PhoneNumber
</th>
<th>
Email
</th>
<th>
Company and Branch
</th>
<th></th>
<th></th>
</tr>
</thead>
#for (var i = 0; i < Model.identityUsers.Count(); i++)
{
<tr>
<td>
<a href="#Url.Action("Edit", "User" , new {id=Model.UserPersons[i].UserPersonId})">
#Html.DisplayFor(x => Model.identityUsers[i].UserName)
</a>
</td>
<td>
<a href="#Url.Action("Edit", "User" , new {id=Model.UserPersons[i].UserPersonId})">
#Html.EditorFor(x => Model.identityUsers[i].PasswordHash, new { htmlAttributes = new { #class = "form-control", placeholder = "Password", Type = "password" } })
</a>
</td>
<td>
<a href="#Url.Action("Edit", "User" , new {id=Model.UserPersons[i].UserPersonId})">
#Html.DisplayFor(x => Model.UserPersons[i].Title)
</a>
</td>
<td>
<a href="#Url.Action("Edit", "User" , new {id=Model.UserPersons[i].UserPersonId})">
#Html.DisplayFor(x => Model.UserPersons[i].Name)
</a>
</td>
<td>
<a href="#Url.Action("Edit", "User" , new {id=Model.UserPersons[i].UserPersonId})">
#Html.DisplayFor(x => Model.UserPersons[i].Surname)
</a>
<td>
#*<a href="#Url.Action("Edit", "User" , new {id=Model.identityUsers[i].Id})">
#Html.DisplayFor(x => Model.identityUsers[i].Email)
</a>*#
</td>
<td>
#*<a href="#Url.Action("Edit", "User" , new {id=Model.identityUsers[i].Id})">
#Html.DisplayFor(x => Model.identityUsers[i].PhoneNumber)
</a>*#
</td>
<td>
#*<a href="#Url.Action("Edit", "User" , new {id=item.ID})">
#Html.DisplayFor(x => item.PhoneNumber)
</a>*#
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id =
Model.identityUsers[i].Id })
</td>
<td>
#Html.ActionLink("Delete", "Delete", new { id =
Model.identityUsers[i].Id })
</td>
</tr>
}
</table>
</div>
The Controller of the view I can't get laoded
public class UserController : Controller
{
private IdentityUserBo identityUserBo;
private PersonBo personBo;
private IdentityUserPersonBo identityuser_personBo;
IdentityUserPersonViewModel model = new IdentityUserPersonViewModel();
public UserController(IdentityUserBo boIdentityUser, PersonBo boPerson, IdentityUserPersonBo boIdentityUserPerson )
{
this.identityUserBo = boIdentityUser ?? throw new ArgumentNullException("boIdentityUser");
this.personBo = boPerson ?? throw new ArgumentNullException("boPerson");
this.identityuser_personBo = boIdentityUserPerson ?? throw new ArgumentNullException("boIdentityUserPerson");
}
public ActionResult Index()
{
return RedirectToAction("List");
}
public ActionResult List()
{
ExBool result = null;
IdentityUserPersonViewModel userPersonViewModel = new IdentityUserPersonViewModel();
result = this.identityUserBo.List(out List<IdentityUser> identityUsers);
if (!result.Success) throw new Exception(result.Messages);
if (identityUsers == null) throw new Exception("Could not load IdentityUsers");
// Ideally see detail eg branch and tel and email from their respective tables
userPersonViewModel.identityUsers = identityUsers;
//Get the Persons, match these via Person.Id -> IdentityUserPerson.FKPersonId + IdentityUserPerson.FKUserId -> IdentityUser.ID
List<Person> persons = null;
result = this.personBo.List(out persons);
//IdentityUserPersonViewModel viewModel = new IdentityUserPersonViewModel();
userPersonViewModel.persons = persons;
// Get the IdentityUserPersons
List<IdentityUserPerson> identityUserPersons = null;
result = this.identityuser_personBo.List(out identityUserPersons);
IdentityUserPerson UPRec = new IdentityUserPerson();
Person PRec = new Person();
userPersonViewModel.UserPersons = new List<UserPerson>();
foreach (IdentityUser rec in userPersonViewModel.identityUsers)
{
UPRec = identityUserPersons.Find(x => x.FKUserID == rec.Id);
if (UPRec != null)
{
//UserId, UserPersonId, + Person.Id + Person.Name + Person.Surname
PRec = persons.Find(y => y.ID == UPRec.FKPersonID);
UserPerson UsrPers = new UserPerson();
UsrPers.UserId = rec.Id;
UsrPers.UserPerson_FKPersonId = UPRec.FKPersonID;
UsrPers.UserPerson_FKUserId = UPRec.FKUserID;
UsrPers.Name = PRec.FirstName;
UsrPers.Surname = PRec.LastName;
UsrPers.Title = PRec.TitleCode;
userPersonViewModel.UserPersons.Add(UsrPers);
}
else
{
UserPerson UsrPers = new UserPerson();
userPersonViewModel.UserPersons.Add(UsrPers);
}
}
return View(userPersonViewModel);
}
Check your console what error you got.
and also change this in tab4
#{
#Html.Partial("List", new Catalyst.Mvc.IdentityUserPersonViewModel())
}

Passing HTML string with res.render's options. But html elements are is getting converted to html codes so text is getting rendered on the email/view

Creating the HTML string.
_.each(order.parcel.pieces, function (piece, index) {
piecesHtmlText += '<div style="float: left;margin: 0px 10px;width: 150px;">'+
'<p style="font-weight: bold;">Piece - '+index+'</p>'+
'<p>Length: <span>'+piece.piece_length+' '+piece.length_unit+'</span></p>'+
'<p>Width: <span>'+piece.piece_width+' '+piece.length_unit+'</span></p>'+
'<p>Height: <span>'+piece.piece_height+' '+piece.length_unit+'</span></p>'+
'<p>Content: <span>'+piece.content+'</span></p>'+
'<p>Reason: <span>'+piece.reason+'</span></p>'+
'</div>';
});
Rendering the html and sending an email. ()
res.render(path.resolve('modules/orders/server/templates/order-successful-email'),
{
name: req.user.displayName,
order: order,
date: date+'/'+month+'/'+year,
piecesHtmlText: piecesHtmlText,
appName: config.app.title,
invoice_url: 'http://' + req.headers.host + '/invoice/' + order._id
}, function (err, emailHTML) {
console.log(emailHTML);
var mailOptions = {
to: req.user.email,
from: config.mailer.from,
subject: 'Order successful',
html: emailHTML
};
smtpTransport.sendMail(mailOptions, function (err) {
if (!err) {
res.redirect('/parcels/' + order._id + '/stage5');
} else {
res.redirect('/parcels/' + order._id + '/stage5');
}
});
}
The HTML file:
<div style="color: #4d4d4d;margin-bottom: 50px;">
<p>Dear {{name}} </p>
<p>Your order {{order._id+""}} has been placed successfully with {{shippingPartner}} on Date {{date}}. </p>
<p>Please ensure that your contact and address information is accurate for a smooth delivery experience.</p>
<table style="max-width: 500px;margin: auto;border-collapse: collapse;">
<tr>
<td>
<img src="http://mara.whyable.com/modules/core/img/brand/logo.png" style="width: 100px;" />
</td><!-- Column for logo. -->
<td></td>
</tr><!-- First row for logo -->
<tr style="background-color: #30bee4;color: white;">
<td colspan="2" style="padding: 10px;">
<p style="font-weight: bold;">Package contents</p>
<hr style="color: white;"/>
{{piecesHtmlText}}
</td>
</tr><!-- Second row for pieces information -->
</table>
When I pass HTML string as an option to res.render, the < and > are converted into HTML codes. Ex < etc
Is there a way I can pass HTML string as an option to res.render?
Thank you.

Resources