AngularJS - object not passed to modal dialog - javascript

I have a problem with an AngularJS app I'm making. It shows a list of contacts, and for each contact there is a button whereupon clicking the button a modal pops up with a form. This form should show the existing contact information, and if you want to change something you type the new information and press submit.
The problem, however, is that the existing information is not shown in the form, hence editing it doesn't work. I imagine that the issue is that the modal does not inherit the scope from the parent page, but I don't know what to do in order to fix that. I have tried playing around with the attributes on the input fields (for example prepending ng-model by $parent. and defining an ng-init value), but to no avail, so I hope some of the experts here will be able to point me on the right track.
Thank you in advance.
Now let me show you my code, so you can see the context I'm talking about. Here is the html that displays the list of contacts:
<div class="panel panel-default" ng-controller="contactsController">
<div class="panel-body">
<div id="gridContainer" ng-class="{'': state == 'list', 'none': state != 'list'}">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th scope="col"><spring:message code="contacts.name"/></th>
<th scope="col"><spring:message code="contacts.email"/></th>
<th scope="col"><spring:message code="contacts.phone"/></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="contact in page.source">
<td class="tdContactsCentered">{{contact.name}}</td>
<td class="tdContactsCentered">{{contact.email}}</td>
<td class="tdContactsCentered">{{contact.phoneNumber}}</td>
<td class="width15">
<div class="text-center">
<input type="hidden" value="{{contact.id}}"/>
<a ng-href="#updateContactsModal"
ng-click="selectedContact(contact);"
role="button"
title="<spring:message code="update"/> <spring:message code="contact"/>"
class="btn btn-sm btn-warning" data-toggle="modal">
<i class="icon-pencil"></i>
</a>
<a ng-href="#deleteContactsModal"
ng-click="selectedContact(contact);"
role="button"
title="<spring:message code="delete"/> <spring:message code="contact"/>"
class="btn btn-sm btn-danger" data-toggle="modal">
<em class="fa fa-trash"></em>
</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
And the html that defines the modal and the form:
<div id="updateContactsModal"
class="modal fade centering"
role="dialog"
aria-labelledby="updateContactsModalLabel"
aria-hidden="true" style="display: none;">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h3 id="updateContactsModalLabel" class="modal-title">
<spring:message code="update"/> <spring:message code="contact"/>
</h3>
</div>
<div class="modal-body" data-ng-controller="contactsController">
<form name="updateContactForm" novalidate>
<input type="hidden"
required
data-ng-model="contact.id"
name="id"
value="{{contact.id}}"/>
<div>
<div class="form-group">
<label>* <spring:message code="contacts.name"/>:</label>
<input type="text"
autofocus
required
class="form-control"
data-ng-model="contact.name"
name="name"
placeholder="<spring:message code='contact'/> <spring:message code='contacts.name'/> "/>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.name.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
<div class="form-group">
<label>* <spring:message code="contacts.email"/>:</label>
<div class="input-append">
<input type="text"
required
class="form-control"
ng-model="contact.email"
name="email"
placeholder="<spring:message code='sample.email'/> "/>
</div>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.email.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
<div class="form-group">
<label>* <spring:message code="contacts.phone"/>:</label>
<div class="input-append">
<input type="text"
required
class="form-control"
ng-model="contact.phoneNumber"
name="phoneNumber"
placeholder="<spring:message code='sample.phone'/> "/>
</div>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.phoneNumber.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
</div>
</form>
<div class="modal-footer">
<input type="submit"
class="btn btn-primary"
ng-click="updateContact(updateContactForm);"
value='<spring:message code="update"/>'/>
<button class="btn btn-default"
data-dismiss="modal"
ng-click="exit('#updateContactsModal');"
aria-hidden="true">
<spring:message code="cancel"/></button>
</div>
</div>
<span class="alert alert-error dialogErrorMessage"
ng-show="errorOnSubmit">
<spring:message code="request.error"/>
</span>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
And finally the relevant parts of the controller:
App.controller('contactsController', ["$scope", "$http", function($scope,$http) {
$scope.pageToGet = 0;
$scope.state = 'busy';
$scope.lastAction = '';
$scope.url = "/uaiContacts/protected/contacts/";
$scope.errorOnSubmit = true;
$scope.errorIllegalAccess = false;
$scope.displayMessageToUser = false;
$scope.displayValidationError = false;
$scope.displaySearchMessage = false;
$scope.displaySearchButton = false;
$scope.displayCreateContactButton = false;
$scope.contact = {};
$scope.searchFor = "";
$scope.getContactList = function () {
var url = $scope.url;
$scope.lastAction = 'list';
$scope.startDialogAjaxRequest();
var config = {params: {page: $scope.pageToGet}};
$http.get(url, config)
.success(function (data) {
$scope.finishAjaxCallOnSuccess(data, null, false);
})
.error(function () {
$scope.state = 'error';
$scope.displayCreateContactButton = false;
});
};
$scope.populateTable = function (data) {
if (data.pagesCount > 0) {
$scope.state = 'list';
$scope.page = {source: data.contacts, currentPage: $scope.pageToGet, pagesCount: data.pagesCount, totalContacts : data.totalContacts};
if($scope.page.pagesCount <= $scope.page.currentPage){
$scope.pageToGet = $scope.page.pagesCount - 1;
$scope.page.currentPage = $scope.page.pagesCount - 1;
}
$scope.displayCreateContactButton = true;
$scope.displaySearchButton = true;
} else {
$scope.state = 'noresult';
$scope.displayCreateContactButton = true;
if(!$scope.searchFor){
$scope.displaySearchButton = false;
}
}
if (data.actionMessage || data.searchMessage) {
$scope.displayMessageToUser = $scope.lastAction != 'search';
$scope.page.actionMessage = data.actionMessage;
$scope.page.searchMessage = data.searchMessage;
} else {
$scope.displayMessageToUser = false;
}
};
$scope.exit = function (modalId) {
$(modalId).modal('hide');
$scope.contact = {};
$scope.errorOnSubmit = false;
$scope.errorIllegalAccess = false;
$scope.displayValidationError = false;
};
$scope.finishAjaxCallOnSuccess = function (data, modalId, isPagination) {
$scope.populateTable(data);
$("#loadingModal").modal('hide');
if(!isPagination){
if(modalId){
$scope.exit(modalId);
}
}
$scope.lastAction = '';
};
$scope.startDialogAjaxRequest = function () {
$scope.displayValidationError = false;
$("#loadingModal").modal('show');
$scope.previousState = $scope.state;
$scope.state = 'busy';
};
$scope.handleErrorInDialogs = function (status) {
$("#loadingModal").modal('hide');
$scope.state = $scope.previousState;
// illegal access
if(status == 403){
$scope.errorIllegalAccess = true;
return;
}
$scope.errorOnSubmit = true;
$scope.lastAction = '';
};
$scope.addSearchParametersIfNeeded = function(config, isPagination) {
if(!config.params){
config.params = {};
}
config.params.page = $scope.pageToGet;
if($scope.searchFor){
config.params.searchFor = $scope.searchFor;
}
};
$scope.selectedContact = function (contact) {
$scope.contact = angular.copy(contact);
debugger;
};
$scope.updateContact = function (updateContactForm) {
if (!updateContactForm.$valid) {
debugger;
$scope.displayValidationError = true;
return;
}
$scope.lastAction = 'update';
var url = $scope.url + $scope.contact.id;
$scope.startDialogAjaxRequest();
var config = {};
$scope.addSearchParametersIfNeeded(config, false);
$http.put(url, $scope.contact, config)
.success(function (data) {
$scope.finishAjaxCallOnSuccess(data, "#updateContactsModal", false);
})
.error(function(data, status, headers, config) {
$scope.handleErrorInDialogs(status);
});
};
$scope.getContactList();
}]);

The modal doesn't share the same scope as the contacts table because each time Angular finds another ng-controller directive, it creates a new scope.
You're declaring ng-scope in both the contacts table and the modal, which causes angular to create different scopes.
See this answer for more details:
https://stackoverflow.com/a/14462341/4938335
There are a few ways to solve this...
1) Put the modal HTML inside the parent element where you're already declaring ng-controller the first time - that way it will be part of the same scope
2) Use UI Bootstrap's modal directive to generate the modal with its own controller and pass in $scope.contact from your contactsController. See example here https://angular-ui.github.io/bootstrap/#/modal
3) Create a service that stores $scope.contact and inject that into a separate controller that you create for the modal. Here's someone else's fiddle that shows this:
http://jsfiddle.net/whnSs/

Related

Modal Pop-Up Not Passing iFormFile Data On JavaScript Ajax Intercept

This is sort of an add-on to my previous question:
Modal Pop-Up Not Closing Properly After Form Submission
I'm trying to reuse the modal pop-up functionality for another pop-up on the same page. This time I am using it to upload a file. This is the javascript in question:
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
})
I inadvertently misspelled "relative" on the submit button of this form:
#model Models.AttachmentModel
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Upload File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Attachment">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<div>
<p>Upload a file using this form:</p>
<input type="file" name="file" />
<span asp-validation-for="#Model.aFileData" class="text-danger"></span>
</div>
<div>
<p>Enter a file description</p>
<input id="attachment" asp-for="#Model.aIssueAttachmentDescription" class="form-control" />
<span asp-validation-for="#Model.aIssueAttachmentDescription" class="text-danger"></span>
<input id="issueid" type="hidden" asp-for="#Model.issueId" class="form-control" value="#ViewBag.id" />
</div>
<!--Modal Footer Start-->
<div class="modal-footer">
#*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*#
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
<input type="submit" class="btn btn-success realative" id="btnSubmit" data-save="modal" value="Upload">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
With the word "relative" misspelled, the file information is being sent to the action in the controller(see below). My guess is the Javscript isn't catching the click action ($('body').on('click', '.relative', function (e)). When I spell "relative" correctly the file information is NULL:
public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
{ //do something
}
What needs to change with the Javascript (or my form/controller) to get the file information? In both cases the collection information is being passed. Is there a way to get the file information added to the collection?
--------- More Info based on #Rena answer
Let me expand some more on the original code and how this works. I have a page that has a modal section that will be populated with different partial views depending upon what I want displayed in the modal. On the Main page it has the following Javascript section:
<script>
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
})
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
I took what was provided by #Rena and inserted it into this section, but found that the Modal wouldn't close (although the data from the form in the partial view was now getting passed). I tried changing the .realative to another value on both the partial view and the javascript, but it made no difference. I then tried what #mj313 suggested in the preceding posts by changing the provided script like this to redirect to /Issue/Edit but that didn't work either.:
}).done((response, textStatus, xhr) => {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
So while I can now pass data I can't close the Modal.
UPDATE
Here is a slimmed down version of the Edit page where all of this starts
#model MYAPP.ViewModels.IssueViewModel
#{
ViewData["Title"] = "Issue Detail Page";
}
<script type="text/javascript">
$(document).ready(function () {
$("#UploadSection").load("/Attachment/GetAttachments/" + #Model.IssueData.issueId);
});
$(function () {
//Some code
});
function onSelectChange(element) {
//Some code
}
</script>
<div asp-validation-summary="All" class="text-danger"></div>
<hr />
<div class="row">
<div>
<form asp-action="Edit">
<input type="hidden" asp-for="IssueData.issueId" />
#*Some Code*#
#*Placeholder for Modal Pop-up*#
<div id="modal-container" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
</div>
</div>
</div>
#*This table contains the first control that generates a modal which contains the _CreateEdit.cshtml*#
<table width="100%">
<tr>
<td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
<div class="form-group">
<label asp-for="IssueData.issueStatus" class="control-label">Current Issue Status</label>
-
#if (#Model.IssueData.StatusList[0].UpdatedByName != "")
{
<text>Updated by: </text> #Model.IssueData.StatusList[0].UpdatedByName <text> - </text>#Model.IssueData.StatusList[0].StatusDate.Value.ToShortDateString()
}
else
{
<text>Created by: </text> #Model.IssueData.StatusList[0].EnteredByName <text> - </text>#Model.IssueData.StatusList[0].StatusDate.Value.ToShortDateString()
}
</div>
</td>
<td style="background-color: midnightblue; padding-right:5px">
#if (#Model.IssueData.StatusList[0].StatusDate != DateTime.Today)
{
Add New Status
}
else
{
<a href="#Url.Action("CreateEdit", new { controller = "Issue", issueid = Model.IssueData.issueId, addedit = "edit" })"
class="modal-link btn btn-success">Edit Current Status</a>
}
</td>
</tr>
</table>
<br />
#*This table contains the second control that generates a modal which contains the _UploadFile.cshtml*#
<table id="upload" width="100%">
<tr>
<td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
<label class="control-label">Upload Attachments</label>
</td>
<td style="background-color: midnightblue; padding-right:5px">
<a href="#Url.Action("FileUpload", new { controller = "Attachment", issueid = Model.IssueData.issueId })"
class="modal-link btn btn-success">Upload Files</a>
</td>
</tr>
</table>
#*This section contains a partial view _DisplayFiles.cshtml. The _DisplayFiles.cshtml has controls that generate 2 more modals. The modals contain either the
_DeleteFile.cshtml or _EditFile.cshtml partial views*#
<div id="UploadSection"></div>
#{
await Html.RenderPartialAsync("_DisplayFiles");
}
<div class="form-group">
<input type="submit" value="Save Changes" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
//Using this to scroll the page on the close of the modal/page refresh
$(document).ready(function () {
var JumpTo = '#ViewBag.JumpToDivId';
if (JumpTo != "") {
$(this).scrollTop($('#' + JumpTo).position().top);
}
});
//Using this to Capture the click that opens the modals
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
//Using this to Capture the click that Submits the _EditFile,_DeleteFile,_CreateEdit forms on the modal
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
var issueid = "";
issueid = $('body').find('[name="issueidSaved"]').val();
var jumpto = $('body').find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
if (issueid == "")
{
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto=" + jumpto;
}
}
});
})
//Using this to Capture the click that Submits the _UploadFile form on the modal
$(function () {
$('body').on('click', '.fileupload', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var fdata = new FormData();
$('input[name="file"]').each(function (a, b) {
var fileInput = $('input[name="file"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("file", file);
}
});
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$("form input[type='hidden']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
url: actionUrl,
method: "POST",
contentType: false,
processData: false,
data: fdata
}).done((response, textStatus, xhr) => {
var isValid = $(response).find('[name="IsValid"]').val() == 'True';
var issueid = $(response).find('[name="issueidSaved"]').val();
var jumpto = $(response).find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto="+jumpto;
}
});
})
});
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
}
Here is the code for _UpdateFile.cshtml
#model MYAPP.Models.AttachmentModel
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<input name="issueidSaved" type="hidden" value="#ViewBag.ID" />
<input name="jumpto" type="hidden" value="#ViewBag.JumpToDivId" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Upload File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Attachment">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<div>
<p>Upload a file using this form:</p>
<input type="file" name="file" />
<span asp-validation-for="#Model.aFileData" class="text-danger"></span>
</div>
<div>
<p>Enter a file description</p>
<input id="attachment" asp-for="#Model.aIssueAttachmentDescription" class="form-control" />
<span asp-validation-for="#Model.aIssueAttachmentDescription" class="text-danger"></span>
<input id="issueid" type="hidden" asp-for="#Model.issueId" class="form-control" value="#ViewBag.id" />
</div>
<!--Modal Footer Start-->
<div class="modal-footer">
#*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*#
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
<input type="submit" class="btn btn-success fileupload" id="btnSubmit" data-save="modal" value="Upload">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
Here is the code for the file Upload
[HttpPost]
public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
{
if (file == null)
{
ModelState.AddModelError("aFileData", "Please select a file.");
}
if (collection["aIssueAttachmentDescription"] == "")
{
ModelState.AddModelError("aIssueAttachmentDescription", "Please provide a description for the file.");
}
if (!ModelState.IsValid)
{
return PartialView("_UploadFile");
}
var formFileContent =
await FileHelpers.ProcessFormFile<BufferedSingleFileUploadDb>(
file, ModelState, _permittedExtensions,
_fileSizeLimit);
var thefile = new AttachmentModel
{
aFileData = formFileContent,
aFileName = file.FileName,
aIssueAttachmentDescription = collection["aIssueAttachmentDescription"],
aFileSize = file.Length,
aFileType=file.ContentType,
issueId = collection["issueId"]
};
string result = _adoSqlService.InsertFile(thefile);
ViewBag.ID = collection["issueId"];
ViewBag.JumpToDivId = "upload";
return PartialView("_UploadFile");
}
You can see in the code above that I add in model errors if the file is not selected or the description is not filled in. These are not being shown.
I can live with the collection returning the entire Edit forms data, but ideally it should only return the fields on the _UploadFile.cshtml form (aIssueAttachmentDescription, issueId)
Anything you can provide that fixes the display of the model errors as well as a way to simplify my code would be greatly appreciated.
With the word "relative" misspelled, the file information is being sent to the action in the controller(see below). My guess is the Javscript isn't catching the click action ($('body').on('click', '.relative', function (e)). When I spell "relative" correctly the file information is NULL
The <input type="submit"> defines a submit button which submits all form values to a form-handler.So although you misspelled the word,it also could submit to the action successfully by default.
For how to use ajax to pass form data with file,you could follow:
#model Mvc3_0.Controllers.HomeController.AttachmentModel
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Upload File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Attachment">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<div>
<p>Upload a file using this form:</p>
<input type="file" name="file" />
<span asp-validation-for="#Model.aFileData" class="text-danger"></span>
</div>
<div>
<p>Enter a file description</p>
<input id="attachment" asp-for="#Model.aIssueAttachmentDescription" class="form-control" />
<span asp-validation-for="#Model.aIssueAttachmentDescription" class="text-danger"></span>
<input id="issueid" type="hidden" asp-for="#Model.issueId" class="form-control" value="#ViewBag.id" />
</div>
<!--Modal Footer Start-->
<div class="modal-footer">
#*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*#
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
<input type="submit" class="btn btn-success realative" id="btnSubmit" data-save="modal" value="Upload">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
</div>
</div>
#section Scripts
{
<script type="text/javascript">
$(function () {
$('body').on('click', '.realative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var fdata = new FormData();
$('input[name="file"]').each(function (a, b) {
var fileInput = $('input[name="file"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("file", file);
}
});
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$("form input[type='hidden']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
url: actionUrl,
method: "POST",
contentType: false,
processData: false,
data: fdata
}).done((response, textStatus, xhr) => {
$("#exampleModal").modal('hide'); //update here...
});
})
});
</script>
}
Update1:
.done((response, textStatus, xhr) => {
$("#exampleModal").modal('hide'); //update here...
});
Update2:
By using your code,I find that you add the modal html in a form which is in the main page.This will cause the form in modal which is in _UploadFile.cshtml could not generate well in my project.Here is the whole working demo:
Main Page:
#model AttachmentModel
<div class="row">
<div>
//change here.....
<div id="modal-container" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
</div>
</div>
</div>
<form asp-action="Edit">
<br />
#*This table contains the second control that generates a modal which contains the _UploadFile.cshtml*#
<table id="upload" width="100%">
<tr>
<td width="90%" style="padding:5px 5px 0px 5px;background-color:midnightblue;color:white">
<label class="control-label">Upload Attachments</label>
</td>
<td style="background-color: midnightblue; padding-right:5px">
<a href="#Url.Action("FileUpload", new { controller = "Attachment", issueid = "1" })"
class="modal-link btn btn-success">Upload Files</a>
</td>
</tr>
</table>
<div class="form-group">
<input type="submit" value="Save Changes" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Js in Main Page:
#section Scripts
{
<script type="text/javascript">
$(function () {
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
$('body').on('click', '.fileupload', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
console.log(actionUrl);
var fdata = new FormData();
$('input[name="file"]').each(function (a, b) {
var fileInput = $('input[name="file"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("file", file);
}
});
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$("form input[type='hidden']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
url: actionUrl,
method: "POST",
contentType: false,
processData: false,
data: fdata
})
.done((response, textStatus, xhr) => {
var isValid = $(response).find('[name="IsValid"]').val() == 'True';
var issueid = $(response).find('[name="issueidSaved"]').val();
var jumpto = $(response).find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
}
});
})
})
</script>
}
_UploadFile.cshtml:
#model AttachmentModel
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<input name="issueidSaved" type="hidden" value="#ViewBag.ID" />
<input name="jumpto" type="hidden" value="#ViewBag.JumpToDivId" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Upload File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload" method="post" enctype="multipart/form-data" asp-controller="Home">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<div>
<p>Upload a file using this form:</p>
<input type="file" name="file" />
<span asp-validation-for="#Model.aFileData" class="text-danger"></span>
</div>
<div>
<p>Enter a file description</p>
<input id="attachment" asp-for="#Model.aIssueAttachmentDescription" class="form-control" />
<span asp-validation-for="#Model.aIssueAttachmentDescription" class="text-danger"></span>
<input id="issueid" type="hidden" asp-for="#Model.issueId" class="form-control" value="#ViewBag.id" />
</div>
<!--Modal Footer Start-->
<div class="modal-footer">
#*<button type="submit" class="btn btn-success fileuploadmodal" data-save="modal">Upload</button>*#
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
<input type="submit" class="btn btn-success fileupload" id="btnSubmit" data-save="modal" value="Upload">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
Controller:
[HttpPost]
public async Task<IActionResult> FileUpload(IFormFile file, IFormCollection collection)
{
var thefile = new AttachmentModel
{
aFileData = "asdad",
aIssueAttachmentDescription = collection["aIssueAttachmentDescription"],
issueId = collection["issueId"]
};
ViewBag.ID = collection["issueId"];
ViewBag.JumpToDivId = "upload";
return PartialView("_UploadFile");
}
Result:

Trying to prevent modal close on button click - javascript

I'm working on a small project in ASP.NET MVC, and in one part I need help of javascript.
Acctually there is modal with three inputs, old password, new and confirm new password,
and in case all fields are empty I need to prevent user from closing modal, I tried to solve it like this:
function comparePasswords(currentPassword) {
//Here I will loop throught all of my three inputs to check are they empty
var formInvalid = false;
$('#allInputs input').each(function () {
if ($(this).val() === '') {
formInvalid = true;
}
});
if (formInvalid) {
alert('One or more fields are empty.');
$('#ChangePassword').modal({
backdrop: 'static',
keyboard: false // I need to prevent user from clicking ESC or something
})
}
}
But I get following error (check the image):
EDIT:
FULL CODE:
<div class="form-group">
<label for="UserPassword">Pw:</label>
#Html.TextBoxFor(model => model.PasswordHash, new { #class = "form-control custom-input", data_toggle = "modal", data_target = "#ChangePassword", ariaDescribedby = "basic-addon1" })
</div>
#*Modal for ChangePassword which is opening when user clicks on control above ^*#
<div id="ChangePassword" class="modal fade" role="dialog">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Updating password</h4>
</div>
<div class="modal-body" id="allInputs">
#*Modal Old Password*#
<div class="form-group">
<label for="UserPassword">Old password:</label>
<input type="password" class="form-control custom-input modal-trigger" value="Eldin123" name="oldPassword" id="OldPassword" data-toggle="modal">
</div>
#*Modal New Password*#
<div class="form-group">
<label for="UserPassword">New password:</label>
<input type="password" class="form-control custom-input modal-trigger" value="" name="newPassword" id="NewPassword" data-toggle="modal">
</div>
#*Modal Repeat New Password*#
<div class="form-group">
<label for="UserPassword">Confirm new password:</label>
<input type="password" class="form-control custom-input modal-trigger" value="" name="confirmPassword" id="ConfirmNewPassword" data-toggle="modal">
</div>
#*Modal - submit*#
<div class="confirm-login">
<button type="button" class="btn custom-btn-big" onclick="comparePasswords();">NEXT</button>
</div>
</div>
</div>
</div>
</div>#*end of Modal for ChangePassword*#
#*Confirm button*#
<div class="confirm-login">
<button class="btn custom-btn-big" data-target="#">SAVE ALL CHANGES</button>
</div>
</div>
</div>
</div> #*End of User / Administration*#
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script>
function fieldInvalid() {
var formInvalid = false;
$('#allInputs input').each(function () {
if ($(this).val() === '') {
formInvalid = true;
console.log(formInvalid);
}
});
}
function passwordsInvalid() {
var invalidPassword = true;
var oldPw = $("#OldPassword").val();
var newPw = $("#NewPassword").val();
var confirmNewPw = $("#ConfirmNewPassword").val();
if (oldPw != newPw) {
alert('Postojeći password nije ispravan.');
}
else if (oldPw != confirmNewPw) {
alert('Password koji ste unijeli se ne slaže.');
}
else {
invalidPassword = false;
}
return invalidPassword;
}
var comparePasswords = function () {
if (fieldInvalid()) {
alert('One or more fields is empty.');
}
else {
if (!passwordsInvalid()) {
$("#ChangePassword").modal('hide');
}
}
}
</script>
}
So when someone clicks on password input, modal will be opened, and from that modal after informations are there user should click on button "NEXT" and there is event onclick which is calling comparePasswords method.
You are missing bootstrap library file.
Order of the file should be
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
Same Problem (missing bootstrap.js) http://jsfiddle.net/1aeur58f/676/
Problem resolved (by adding bootstrap.js) http://jsfiddle.net/1aeur58f/677/
Hope this will help you.

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

AngularJS : View doesn't update when a value in $scope changes

I have an html file with a view that gets it's values from an AngularJS scope.
<form ng-controller="EmployeesController as emp" class="signed-in" ng-submit="logOutUser()">
<div class="row">
<div class="col-md-10 text-left">
<h5>Your Games, {{emp.username}}</h5>
</div>
<div class="col-md-2">
<button class="btn btn-md btn-primary btn-block" type="submit">Log Out</button>
</div>
</div>
<div class="row store">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">Games To Buy</div>
<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<th>Game Name</th>
<th>Game Status {{what}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="game in emp.games">
<td>{{game}}</td>
<td>
<button ng-click="buyGame(game.gameId)" type="button" class="btn btn-sm btn-primary btn-block" href="#">Buy</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</form>
.
And the js file :
var app = angular.module("MyApp", ['ngRoute']);
app.controller("EmployeesController", function($scope, $http) {
this.games = [{gameName: 'aaa', gameId: '1'},{gameName: 'aaa', gameId: '1'},{gameName: 'aaa', gameId: '1'}];
this.ownedGames = [];
var that = this;
$scope.sellGame = function(gameId) {
var index = that.ownedGames.indexOf(gameId);
that.ownedGames.splice(index, 1);
$.jStorage.set(that.username, that.ownedGames);
}
$scope.$on('$viewContentLoaded', function() {
if($.jStorage.get('Employee') == null)
$scope.logged = false;
else
$scope.logged = true;
$http.get('employees.json').
success(function(data, status, headers, config) {
that.games = data.games;
that.username = $.jStorage.get('Employee');
if($.jStorage.get(that.username) != null)
that.ownedGames = $.jStorage.get(that.username);
});
});
});
Ok. So basically what the problem is, is that the emp.games variable is empty. First of all it gets commented in the rendered HTML page, and second when i debug the page the variable emp.games is empty. Yet the variable that emp.games is supposed to get its values from, the $scope.games is filled with values as it should be. So the problem is that my emp.games doesn't see that $scope.games was updated in that http request, so IT doesn't update. I googled as much as i could and found out that i should use $scope.apply, but wherever i used it i got the error $digest already in progress... any ideas?
Thanks
Try check diggest
if (!$scope.$$phase) {
$scope.$apply(function () {
that.games = data.games;
})
}
else
that.games = data.games;
Or you can inject $timeout service and use it like this, it will be better.
$timeout (function () {
that.games = data.games;
}, 0)
Your controller definition is not valid, please use like this.
app.controller("EmployeesController", ['$scope','$http','$timeout', function($scope, $http, $timeout){
//....
}]

$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