Unable to load a Knockout Component - Unknown template value: [object Object] - javascript

This is how I am using the component and sending the parameters using a Custom Element:
<div class="container" data-bind="with: DevoteeList">
<div class="row" style="padding: 10px;">
<div class="col-md-8"></div>
<div class="col-md-4">
<ko-pager params="Data: Devotees,
Modifier: $parent.DevoteeModifier,
PageCount: DevoteesPageCount(),
Url: '#Url.Action("SelectDevotees", "Devotee", new { a = 1 })'"></ko-pager>
</div>
</div>
This is how I am defining a Knockout Component. It is a Pager that I want to use at few places. But, I am receiving the error: Uncaught Error: Unable to process binding "with: function (){return SelectDevotees }"
Message: Unable to process binding "with: function (){return DevoteeList }"
Message: Unable to process binding "component: function () { return l }"
Message: Component 'ko-pager': Unknown template value: [object Object]
ko.components.register('ko-pager', {
viewModel: function (params) {
var self = this;
self.currentPage = ko.observable(1);
self.pages = ko.observableArray([]);
self.PageCount = ko.observable(params.PageCount);
//self.currentPage.subscribe(function (nv) {
// self.GetPage(self.parent);
//});
self.GetPages = function () {
for (var i = 1; i <= params.PageCount ; i++) {
self.pages.push(i);
}
return self.pages;
};
self.FirstPage = function () {
self.GetPage(1);
};
self.PrevPage = function () {
if (self.currentPage() > 1) {
var pn = self.currentPage() - 1;
self.GetPage(pn);
}
};
self.LastPage = function () {
self.GetPage(params.PageCount);
};
self.NextPage = function () {
if (self.currentPage() < params.PageCount) {
var pn = self.currentPage() + 1;
self.GetPage(pn);
}
};
self.GetPage = function (pg) {
if (pg == null)
pg = self.currentPage();
else
self.currentPage(pg);
var url = params.Url + '&pageNumber=' + pg;
$.get(url, function (data) {
var t = ko.mapping.fromJS(data);
if (params.Modifier) {
params.Modifier(t);
}
params.Data(t());
});
};
},
template: { element: document.getElementById('ko-ajax-pager') }
});
<div id="ko-ajax-pager" style="display: none;">
<div class="row" style="padding: 10px;" data-bind="visible: PageCount > 1">
<div class="col-md-1"></div>
<div class="col-md-2">
<input type="button" value="First" class="btn" data-bind="click: FirstPage" />
</div>
<div class="col-md-2">
<input type="button" value="Prev" class="btn" data-bind="click: PrevPage" />
</div>
<div class="col-md-2">
<select data-bind="options: GetPages(), value: currentPage, event: { change: GetPage(null) }">
</select>
</div>
<div class="col-md-2">
<input type="button" value="Next" class="btn" data-bind="click: NextPage" />
</div>
<div class="col-md-2">
<input type="button" value="Last" class="btn" data-bind="click: LastPage" />
</div>
<div class="col-md-1"></div>
</div>
</div>
Can someone please figure out, what is wrong?

Related

PHP laravel and JQuery AJAX append form input

Hey guys I am just wondering how I can append a view within Laravel to my page using AJAX.
How can I append just input nema="result" and insert data into the database with laravel.
Error: [HTTP/1.1 422 Unprocessable Entity 323ms]
My blad file
<form id="repeater_form" class="row" action="{{route('agreement.store')}}" method="post" enctype="multipart/form-data">
#csrf
<div class="col-sm-3 form-group">
<label>Year</label>
<select class="form-control select2" name="year" >
<option value="">--select--</option>
#foreach ($years as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
#endforeach
</select>
</div>
<div class="form-group">
<label>target</label>
<input type="text" name="target" id="target" class="form-control" />
</div>
<div id="repeater">
<div class="repeater-heading" align="right">
<button type="button" class="btn btn-primary repeater-add-btn">Add More Skill</button>
</div>
<div class="clearfix"></div>
<div class="items" data-group="programming_languages">
<div class="item-content">
<div class="form-group">
<div class="row">
<input type="text" name="result[]" id="result" class="form-control" required />
<div class="col-md-3" style="margin-top:24px;" align="center">
<button id="remove-btn" class="btn btn-danger" onclick="$(this).parents('.items').remove()">Remove</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12 form-group">
<button name="insert" type="submit" class="btn btn-primary"><i class="fa fa-save"></i> Submit</button>
backe
</div>
</form>
Js File
<script>
$(document).ready(function(){
$("#repeater").createRepeater();
$('#repeater_form').on('submit', function(event){
event.preventDefault();
$.ajax({
url: '{{route('agreement.store')}}',
method:"POST",
data:$(this).serialize(),
success:function(data)
{
$('#repeater_form')[0].reset();
$("#repeater").createRepeater();
$('#success_result').html(data);
}
});
});
});
</script>
I am new in laravel Here what am I doing I am going to insert a simple form value into database. Now, what happen when I click on submit button it is not insert data. I have no idea about that. So, How can I do this? Please help me.
Thank You.
My Contoroller
public function store(CreateAgreement $request)
{
$agreements = new Agreement;
$agreements->target = $request->target;
$agreements->result = $request->result;
$agreements->years()->attach(request('year'));
$agreements->save();
return redirect()->route('agreement.index');
}
CreateAgreement Request
public function rules()
{
return [
'year' => ['required'],
'code' => ['required'],
'target' => ['required'],
'result' => ['required'],
];
}
Repeater js
jQuery.fn.extend({
createRepeater: function () {
var addItem = function (items, key) {
var itemContent = items;
var group = itemContent.data("group");
var item = itemContent;
var input = item.find('input,select');
input.each(function (index, el) {
var attrName = $(el).data('name');
var skipName = $(el).data('skip-name');
if (skipName != true) {
$(el).attr("name", group + "[" + key + "]" + attrName);
} else {
if (attrName != 'undefined') {
$(el).attr("name", attrName);
}
}
})
var itemClone = items;
/* Handling remove btn */
var removeButton = itemClone.find('.remove-btn');
if (key == 0) {
removeButton.attr('disabled', true);
} else {
removeButton.attr('disabled', false);
}
$("<div class='items'>" + itemClone.html() + "<div/>").appendTo(repeater);
};
/* find elements */
var repeater = this;
var items = repeater.find(".items");
var key = 0;
var addButton = repeater.find('.repeater-add-btn');
var newItem = items;
if (key == 0) {
items.remove();
addItem(newItem, key);
}
/* handle click and add items */
addButton.on("click", function () {
key++;
addItem(newItem, key);
});
}
});

Get the the in time and out time of employee in Full Calendar according to the user id selected in drop down list

I want to display in time and out time of the user in full calendar. Each and every user has different in time and out time. And the user id is selected in drop down. Right now I'm getting the drop down which is binded with the user name and user id so I have to bind the login time and logout time of the user to the calendar.This is my code where i bind the drop down with data. This is my controller code for binding the drop down with the user id and user name.
public ActionResult AttendanceScreen()
{
List<SelectListItem> userList = Getuser();
return View(userList);
}
[HttpPost]
public ActionResult AttendanceScreen(string ddlCustomers)
{
List<SelectListItem> userList = Getuser();
if (!string.IsNullOrEmpty(ddlCustomers))
{
SelectListItem selectedItem = userList.Find(p => p.Value == ddlCustomers);
ViewBag.Message = "Calender for Name: " + selectedItem.Text;
ViewBag.Message += "\\nID: " + selectedItem.Value;
}
return View(userList);
}
private static List<SelectListItem> Getuser()
{
RegMVCEntities entities = new RegMVCEntities();
List<SelectListItem> customerList = (from p in entities.tblRegistrations.AsEnumerable()
select new SelectListItem
{
Text = p.FName,
Value = p.UserId.ToString()
}).ToList();
//Add Default Item at First Position.
customerList.Insert(0, new SelectListItem { Text = "--Select Employee--", Value = "" });
return customerList;
}
This is my view for displaying the user id and user name as alert.
#using (Html.BeginForm("AttendanceScreen", "Home", FormMethod.Post))
{
#Html.DropDownList("ddlCustomers", Model)
<br />
<br />
<input type="submit" value="Submit" />
}
#if (ViewBag.Message != null)
{
<script type="text/javascript">
window.onload = function () {
alert("#ViewBag.Message");
};
For displaying the calendar the controller code is
public JsonResult GetEvents()
{
using (RegMVCEntities dc = new RegMVCEntities())
{
var events = dc.User_LogTime.ToList();
dc.Configuration.ProxyCreationEnabled = false;
dc.Configuration.LazyLoadingEnabled = false;
return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
}
For displaying the calendar the code of my view is
<h2>Calender</h2>
<div id="calender"></div>
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><span id="eventTitle"></span></h4>
</div>
<div class="modal-body">
<button id="btnDelete" class="btn btn-default btn-sm pull-right">
<span class="glyphicon glyphicon-remove"></span> Remove
</button>
<button id="btnEdit" class="btn btn-default btn-sm pull-right" style="margin-right:5px;">
<span class="glyphicon glyphicon-pencil"></span> Edit
</button>
<p id="pDetails"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="myModalSave" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Save Event</h4>
</div>
<div class="modal-body">
<form class="col-md-12 form-horizontal">
<input type="hidden" id="hdEventID" value="0" />
#*<div class="form-group">
<label>Subject</label>
<input type="text" id="txtSubject" class="form-control" />
</div>*#
<div class="form-group">
<label>LoginTime</label>
<div class="input-group date" id="dtp1">
<input type="text" id="txtStart" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
#*<div class="form-group">
<div class="checkbox">
<label><input type="checkbox" id="chkIsFullDay" checked="checked" /> Is Full Day event</label>
</div>
</div>*#
<div class="form-group" id="divEndDate" style="display:none">
<label>LogoutTime</label>
<div class="input-group date" id="dtp2">
<input type="text" id="txtEnd" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
#*<div class="form-group">
<label>Description</label>
<textarea id="txtDescription" rows="3" class="form-control"></textarea>
</div>*#
<div class="form-group">
<label>Theme Color</label>
<select id="ddThemeColor" class="form-control">
<option value="">Default</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="black">Black</option>
<option value="green">Green</option>
</select>
</div>
<button type="button" id="btnSave" class="btn btn-success">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</form>
</div>
</div>
</div>
</div>
<link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" rel="stylesheet" />
<link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.print.css" rel="stylesheet" media="print" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
#section Scripts{
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
<script>
$(document).ready(function () {
debugger;
var event_array = [];
var selectedEvent = null;
FetchEventAndRenderCalendar();
function FetchEventAndRenderCalendar() {
events = [];
$.ajax({
url: "/Home/GetEvents",
data: "",
type: "GET",
dataType: "json",
async: false,
cache: false,
success: function (data) {
alert("success");
$.each(data, function (i, v) {
event_array.push({
userid: v.UserId,
start: moment(v.LoginTime),
end: moment(v.LogoutTime),
//start: moment(v.start),
//end: v.end != null ? moment(v.end) : null,
//color: v.themecolor,
//allday: v.isfullday
});
})
GenerateCalender(event_array);
},
error: function (error) {
alert('failed');
}
})
}
function GenerateCalender(event_array) {
debugger;
//$('#calender').fullCalendar('destroy');
$('#calender').fullCalendar({
contentHeight: 400,
defaultDate: new Date(),
timeFormat: 'h(:mm)a',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay,agenda'
},
eventLimit: true,
eventColor: '#378006',
events: event_array,
eventClick: function (calEvent, jsEvent, view) {
selectedEvent = calEvent;
$('#myModal #eventTitle').text(calEvent.userid);
var $description = $('<div/>');
$description.append($('<p/>').html('<b>LoginTime:</b>' + calEvent.logintime.format("DD-MMM-YYYY HH:mm a")));
$description.append($('<p/>').html('<b>LogoutTime:</b>' + calEvent.logouttime.format("DD-MMM-YYYY HH:mm a")));
//$description.append($('<p/>').html('<b>Description:</b>' + calEvent.description));
//$('#myModal #pDetails').empty().html($description);
$('#myModal').modal();
},
//selectable: true,
//select: function (logintime, logouttime) {
// selectedEvent = {
//// userid: 0,
//// logintime: logintime,
//// logouttime: logouttime
//// };
//// openAddEditForm();
//// $('#calendar').fullCalendar('unselect');
////},
////editable: false,
eventDrop: function (event) {
var data = {
UserId: event.userid,
LoginTime: event.logintime.format('DD/MM/YYYY HH:mm A'),
LogoutTime: event.logouttime.format('DD/MM/YYYY HH:mm A')
};
SaveEvent(data);
}
});
}
this is the screenshot of my current page
The attendance screen
Right I'm just getting the in time and out time in the database as you can see in screenshot but that is for all the user in Database.I just need to update the calendar with in time and out time of the user id selected in drop down.
I have done it. It was simple I just needed to use session for getting the user id.This is my code:
public ActionResult AttendanceScreen(string ddlCustomers)
{
Session["userid"] = ddlCustomers;
List<SelectListItem> userList = Getuser();
if (!string.IsNullOrEmpty(ddlCustomers))
{
SelectListItem selectedItem = userList.Find(p => p.Value == ddlCustomers);
ViewBag.Message = "Calender for Name: " + selectedItem.Text;
ViewBag.Message += "\\nID: " + selectedItem.Value;
}
return View(userList);
// return RedirectToAction("Index", "Nome", new { userid: userid });
}
public JsonResult GetEvents()
{
string username = User.Identity.Name;
int isessionid = Convert.ToInt32(Session["userid"]);
List<SelectListItem> userList = Getuser();
if (isessionid == 0)
{
return null;
}
else
{
//int userid = int.Parse(username);
RegMVCEntities svc = new RegMVCEntities();
svc.Configuration.ProxyCreationEnabled = false;
svc.Configuration.LazyLoadingEnabled = false;
// var oCampaigns = svc.User_LogTime;
var oReturn =
(from c in svc.User_LogTime.AsEnumerable()
where c.UserId == isessionid
select new
{
LoginTime = c.LoginTime,
Logouttime = c.LogoutTime
}).ToList();
//var events = dc.User_LogTime.ToList();
//dc.Configuration.ProxyCreationEnabled = false;
// dc.Configuration.LazyLoadingEnabled = false;
return new JsonResult { Data = oReturn.ToList(), JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
}

angular UI-Bootstrap modal not binding with controller

I create ng-template and bind it with controller and this template pass through ui-bootstrap modal.
code :-
vm.uploadFile = function () {
var uploadModal = $uibModal.open({
animation: true,
templateUrl: 'upload.html',
bindToController: true,
controller: 'modalCtrl',
controllerAs: 'modalVm',
resolve: {
items: function () {
}
}
});
uploadModal.result.then(function (data) {
data.uploadedBy = 'admin';
data.fileName = data.name;
vulGridService.dataStackForFile.unshift(data);
vulGridService.gridApi.core.refresh();
}, function () {
console.log('Modal dismissed at: ' + new Date());
}
);
}
}
my template is below:-
<script type="text/ng-template" id="upload.html">
<div class="">
<form name="component" ng-submit="modalVm.upload()" novalidate>
<h4 class="margin-null modal-padding bg-primary">Upload File</h4>
<div class="modal-body">
<div class="form-group">
<label>File Type</label><br>
<div class="select-drop-down-icon">
<select ng-model="modalVm.file.fileType"
name="fileType"
class=" cover-block input-field-styling"
ng-change="modalVm.checkFile()" required>
<option value="">Select File Extension</option>
<option value="Qualys">Qualys(.xml)</option>
<option value="Nessus">Nessus(.nessus)</option>
<option value="zip">.zip</option>
</select>
</div>
</div>
<div class="form-group bottom-spacing">
<label>File To Upload</label><br>
<div class="cover-block form-control padding-null">
<input class="border-null text-field-padding" ng-model="modalVm.file.name">
<!--<file-field ng-change="modalVm.checkFile(uploadFile.name)"-->
<!--class="btn btn-primary inline-view pull-right "-->
<!--ng-model="uploadFile">-->
<!--<i class="fa fa-upload" aria-hidden="true"></i>-->
<!--Chose File-->
<!--</file-field>-->
<div class="btn btn-primary inline-view pull-right upload-field">
<i class="fa fa-upload" aria-hidden="true"></i> Chose File
<input grab-file-name get-file-name="modalVm.getFileName" type="file" class="upload">
</div>
<div class="top-space">
<span class="error-text" ng-show="modalVm.extension">
Please Select proper extension file
</span>
</div>
</div>
</div>
<div class="text-center">
<button ng-disabled="modalVm.extension" type="submit"
class="btn btn-success sharp mar-right" aria-label="Close">Save
</button>
<button type="reset" ng-click="modalVm.cancel()" data-dismiss="modal"
class="btn btn-danger sharp mar-right" aria-label="Close">Cancel
</button>
</div>
</div>
</form>
</div>
modalCtrl
function modalCtrl($uibModalInstance, toastr, dateFactory, $scope) {
var modalVm = this;
modalVm.extension = false;
console.log($scope);
modalVm.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
modalVm.upload = function (data) {
// data.uploadedOn = dateFactory.getDate();
// $uibModalInstance.close(data);
// toastr.success('File is Uploaded', 'success', {closeButton: true});
};
modalVm.checkFile = function (file, fileType) {
console.log(file, fileType);
if (file) {
switch (fileType) {
case 'Nessus':
var matchNessus = /[(a-z)(A-Z)(0-9^)]+.(nessus)/g;
if (matchNessus.test(file)) {
console.log('Nessus', file);
modalVm.extension = false;
} else {
modalVm.extension = true;
}
break;
case 'Qualys':
var matchQualys = /[(a-z)(A-Z)(0-9^)]+.(xml)/g;
if (matchQualys.test(file)) {
console.log('Qualys', file);
modalVm.extension = false;
} else {
modalVm.extension = true;
}
break;
case 'zip':
var matchZip = /[(a-z)(A-Z)(0-9^)]+.(zip)/g;
if (matchZip.test(file)) {
console.log('zip', file);
modalVm.extension = false;
} else {
modalVm.extension = true;
}
break;
default:
modalVm.extension = true;
break;
}
}
};
modalVm.getFileName = function (gotFileName) {
console.log($scope.fileType);
modalVm.fileName = gotFileName;
};
}
In which input field not binding with the controller but the function is invoking, please give any hint or solution on it.

AngularJS unable to recognise function

I'm experiencing a similar problem as
The $scope variable is undefined unless I forced it to retrieve from service again
I'm getting the below error from angular js when i'm trying to invoke a function from a service
TypeError: $scope.watchlist.addStock is not a function
This is my below controller
angular.module('stockDogApp')
.controller('WatchlistCtrl', function ($scope,$routeParams,$modal,WatchlistService,CompanyService) {
$scope.companies = CompanyService.query();
$scope.watchlist = WatchlistService.query($routeParams.listId);
console.log($scope.watchlist);
$scope.stocks = $scope.watchlist.stocks;
$scope.newStock = {};
var addStockModal = $modal({
scope : $scope,
templateUrl : 'views/templates/addstock-modal.html',
show: false
});
$scope.showStockModal = function(){
addStockModal.$promise.then(addStockModal.show);
};
$scope.addStock = function(){
$scope.watchlist.addStock({
listId : $routeParams.listId,
company: $scope.newStock.company,
shares: $scope.newStock.shares
});
addStockModal.hide();
$scope.newStock = {};
};
When i log $scope.watchlist - the function does seem to be present in the object
Object {name: "Saklep", description: "Saklep", id: 0, stocks: Array[0]}
addStock: function(stock)
arguments: (...)
caller: (...)
length: 1
name: ""
This is the html for the modal window
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="$hide()">×</button>
<h4 class="modal-title">Add New Stock</h4>
</div>
<form role="form" id="add-stock" name="stockForm">
<div class="modal-body">
<div class="form-group">
<label for="stock-symbol">Symbol</label>
<input type="text"
class="form-control"
id="stock-symbol"
placeholder="Stock Symbol"
ng-model="newStock.company"
bs-options="company as company.label for company in companies"
bs-typeahead
required>
</div>
<div class="form-group">
<label for="stock-shares">Shares Owned</label>
<input type="number"
class="form-control"
id="stock-shares"
placeholder="# Shares Owned"
ng-model="newStock.shares"
required>
</div>
</div>
<div class="modal-footer">
<button type="submit"
class="btn btn-success"
ng-click="addStock()"
ng-disabled="!stockForm.$valid">Add</button>
<button type="button"
class="btn btn-danger"
ng-click="$hide()">Cancel</button>
</div>
</form>
</div>
</div>
</div>
EDIT: Adding the watchlist Service
angular.module('stockDogApp')
.service('WatchlistService', function () {
var loadModel = function(){
var model = {
watchlists : localStorage['StockDog.watchlists'] ? JSON.parse(localStorage['StockDog.watchlists']) : [],
nextId : localStorage['StockDog.nextId'] ? parseInt(localStorage['StockDog.nextId']) : 0
};
_.each(model.watchlists,function(watchlist){
_.extend(watchlist,WatchlistModel);
_.each(watchlist.stocks,function(stock){
_.extend(stock,StockModel);
});
});
return model;
};
var StockModel = {
save: function(){
var watchlist = findById(this.listId);
watchlist.recalculate();
saveModel;
}
};
var WatchlistModel = {
addStock: function(stock){
var existingStock = _.find(this.stocks,function(s){
return s.company.symbol === stock.company.symbol;
});
if (existingStock){
existingStock.shares += stock.shares;
}else{
_.extend(stock,StockModel);
this.stocks.push(stock);
}
this.recalculate();
saveModel();
},
Turns out Angular-Yeoman automatically generates a controllerAs function in app.js and its the reason for the conflict
.when('/watchlist/:listId', {
templateUrl: 'views/watchlist.html',
controller: 'WatchlistCtrl',
// controllerAs: 'watchlist'
})
commenting out controllerAs did the trick

$parent.myFunction not returning row as parameter in KnockoutJs

I'm using knockoutjs for the first time in an attempt to have a list of tasks and then to be able to click on one to show it in a popup form. The issue I'm having is with data-bind="click: $parent.edit", which calls ToDoListViewModel/edit.
When I first started writing the list code, it would pass in the current row's todo object as the first parameter into the edit function. After adding the second view model for my add/edit popup form, it no longer behaves this way. Calling $parent.edit still calls the edit function, however now it passes in an empty object { }.
It seems like I'm running into some sort of conflicting bindings issue, any ideas?
Here is the to do list html:
<table class="table table-striped table-hover" data-bind="visible: isVisible">
<thead>
<tr>
<th>To-Do</th>
<th>Estimate</th>
<th>Deadline</th>
#if (Model == null) { <th>Property</th> }
<th>Tenant</th>
<th style="display: none;">Assigned To</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: todos">
<tr data-bind="visible: isVisible()">
<td><a class="pointer" title="Edit To-Do" data-bind="click: $parent.edit, text: Task"></a></td>
<td data-bind="text: FormattedAmount"></td>
<td data-bind="text: FormattedDueDate"></td>
<td data-bind="visible: $parent.showPropertyColumn, text: PropertyName"></td>
<td data-bind="text: TenantName"></td>
<td>
<div class="btn-group pull-right">
<a class="btn btn-primary pointer default-click-action" data-bind="click: $parent.markComplete">Mark Complete</a>
<button class="btn btn-primary dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a class="pointer" data-bind="click: $parent.edit">Edit To-Do</a></li>
<li><a class="pointer" data-bind="click: $parent.remove">Delete To-Do</a></li>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
And here is the popup html:
#model Housters.Schemas.Models.Property.Listing
<div id="popup" class="modal fade" style="display: none;" data-bind="with: form">
#using (Html.BeginForm("SaveTodo", "Properties", FormMethod.Post, new { Id = "form", #class = "form-horizontal" }))
{
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3>To-Do Information</h3>
</div>
<div class="modal-body">
<input id="id" name="id" type="hidden" data-bind="value: todo().Id" />
<input id="originalListingId" type="hidden" value="#(Model != null ? Model.IdString : "")" />
<div class="control-group #(Model != null ? " hide" : "")">
<label class="control-label" for="listingId">Property</label>
<div class="controls">
#Html.DropDownList("listingId", ViewBag.Listings as SelectList, "None",
new Dictionary<string, Object> { { "data-bind", "value: todo().ListingId" } })
</div>
</div>
<div class="control-group">
<label class="control-label" for="tenantId">Tenant</label>
<div class="controls">
<select id="tenantId" name="tenantId" class="span11" data-bind="value: todo().TenantId">
<option value="">None</option>
</select>
<p class="help-block">Is this task related to a certain tenant?</p>
</div>
</div>
<div class="control-group">
<label class="control-label" for="amount">Estimate to Complete</label>
<div class="controls">
<div class="input-prepend"><span class="add-on">$</span><input type="text" id="amount" name="todo.Amount" maxlength="10"
class="span11 number" data-bind="value: todo().Amount" /></div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="dueDate">Due Date</label>
<div class="controls">
<input type="text" id="dueDate" name="todo.DueDate" maxlength="10"
class="span11 date" data-bind="value: todo().DueDate" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="task">Task<span class="required-asterisk">*</span></label>
<div class="controls">
<textarea id="task" name="todo.Task" rows="4" class="span11 required" data-bind="value: todo().Task"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<a class="btn pointer" data-dismiss="modal">Close</a>
<a id="mark-complete-popup" class="btn btn-primary" data-dismiss="modal" data-bind="visible: (todo().Id && !todo().IsComplete), click: markComplete">Mark Complete</a>
<button type="button" class="btn btn-primary" data-bind="click: save">Save</button>
</div>
}
</div>
And lastly, here is the javascript defining the view models:
function ToDoList () {
if(!(this instanceof arguments.callee))
return new arguments.callee();
var parent = this;
this.showCompleted = ko.observable(false);
this.tenantFilter = new PropertyTenantFilter();
this.viewModel = {
list: new ToDoListViewModel(),
form: new ToDoFormViewModel()
};
this.init = function () {
//get all tenants.
utils.block($("#grid-content"), "Loading");
this.tenantFilter.init(function () {
//initialize view model.
ko.applyBindings(this.viewModel);
//setup controls & events.
$("#dueDate").datepicker();
$("#listingId").change(this.tenantFilter.getByListing.bind(this.tenantFilter)).change();
} .bind(this));
};
function ToDoListViewModel() {
//init.
var self = this;
self.todos = ko.observableArray([]);
//computed.
self.showPropertyColumn = ko.computed(function () {
return $("#originalListingId").val().length == 0;
});
self.isVisible = ko.computed(function () {
return _.find(self.todos(), function (todo) { return todo.isVisible(); }) != null;
});
//operations.
self.add = function () {
//set form field values.
parent.viewModel.form.fill(new schemas.ToDo({}, parent));
//show popup.
$("#popup").modal("show");
};
self.edit = function (todo) {
console.debug("edit: " + JSON.stringify(todo));
//set form field values.
parent.viewModel.form.fill(todo);
//update tenants dropdown for selected listing.
parent.tenantFilter.getByListing();
//show popup.
$("#popup").modal("show");
};
self.markComplete = function (todo) {
parent.markComplete(todo);
};
self.remove = function (todo) {
var result = confirm("Are you sure that you want to delete this To-Do?");
if (result) {
//save changes.
utils.ajax(basePath + "properties/deletetodo",
{ id: todo.Id },
function (success) {
//refresh results.
self.todos.remove(todo);
//show result.
utils.showSuccess('The To-Do has been deleted successfully');
}
);
}
};
self.toggleShowCompleted = function () {
parent.showCompleted(!parent.showCompleted());
$("#showCompletedTodos").text(parent.showCompleted() ? "Show Active" : "Show Completed");
};
self.update = function (todo) {
var existingToDo = _.find(self.todos(), function (item) { return item.Id() == todo.Id(); });
existingToDo = todo;
};
//load todos from server.
utils.ajax(basePath + "properties/gettodos",
{ id: $("#originalListingId").val(), showCompleted: parent.showCompleted() },
function (results) {
var mappedTodos = $.map(results, function (item) { return new schemas.ToDo(item, parent); });
self.todos(mappedTodos);
$("#grid-content").unblock();
}
);
}
function ToDoFormViewModel() {
//init.
var self = this;
self.todo = ko.observable({});
utils.setupPopupForm(self.saved);
//operations.
self.fill = function (todo, isEdit) {
//set form field values.
self.todo = todo;
if (todo.Id()) {
//update tenants dropdown for selected listing.
parent.tenantFilter.getByListing();
}
//show popup.
$("#popup").modal("show");
};
self.save = function (todo) {
self.todo = todo;
$("#form").submit();
};
self.saved = function (result) {
var todo = new schemas.ToDo(result.todo, parent);
if (result.isInsert)
parent.viewModel.list.todos().push(todo);
else
parent.viewModel.list.update(todo);
utils.showSuccess("Your To-Do has been saved successfully.");
};
self.markComplete = function (todo) {
parent.markComplete(todo);
};
}
this.markComplete = function (todo) {
var result = confirm("Are you sure that you want to mark this To-Do complete?");
if (result) {
//save changes.
utils.ajax(basePath + "properties/marktodocomplete", {
id: todo.Id()
},
function () {
todo.IsComplete(true);
//show success.
utils.showSuccess('Your To-Do has been marked completed');
} .bind(this)
);
}
}
this.init();
}
One possible solution is to replace:
data-bind="click: $parent.edit"
with
data-bind="click:$root.viewModel.list.edit"

Categories

Resources