How to avoid GET request on form submit with Backbone - javascript

I am trying to write a editable table using Backbone.js.
This is my Backbone.js app:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Resume builder!</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<style>
.jumbotron {
height: 100vh;
}
body {
background-color: white !important;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #ddd!important
}
</style>
</head>
<body>
<div class="jumbotron">
<div class=container>
<h1>Resume builder</h1>
<table class="table table-bordered">
<thead>
<tr>
<th>Degree</th>
<th>Starting date</th>
<th>Ending date</th>
<th>Details</th>
</tr>
</thead>
<tbody id="informations">
<script type="text/template" id="info-row">
<tr>
<td>
<%=title%>
</td>
<td>
<%=start%>
</td>
<td>
<%=end%>
</td>
<td>
<%=details%>
</td>
<td>
<botton class="btn btn-primary" data-action="modify">edit</botton>
<botton class="btn btn-danger" data-action="delete">delete</botton>
</td>
<tr>
</script>
</tbody>
</table>
<div id="actions">
<botton class="btn btn-primary" id="addInformation">Add information</botton>
</div>
<script type="text/template" id="info-modify">
<div class="modal fade" id="edit-modal" 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">INFORMATION</h4>
</div>
<div class="modal-body">
<form role="form">
<div>
<div class="radio">
<label><input type="radio" data-type="education" name="type" <%= (type == "education") ? "checked" : ""%>> Education</label>
</div>
<div class="radio">
<label><input type="radio" data-type="experience" name="type" <%= (type == "experience") ? "checked" : ""%>> Experience</label>
</div>
</div>
<div class="form-group">
<label>Title for Degree or experience (e.g. Computer Sci. | Software dev.):</label>
<input type="text" class="form-control" value="<%=title%>" name="title">
</div>
<div class="form-group">
<label>Start date:</label>
<input type="number" class="form-control" value="<%=start%>" name="start">
</div>
<div class="form-group">
<label>End date:</label>
<input type="number" class="form-control" value="<%=end%>" name="end">
</div>
<div class="form-group">
<label>Details:</label>
<textarea rows="5" class="form-control" name="details"><%=details%></textarea>
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</script>
</div>
</div>
<div id="modal">
</div>
</body>
<script>
$(function() {
var baseModalView = Backbone.View.extend({
el: $("#modal"),
className: 'modal fade hide',
template: _.template($("#info-modify").html()),
events: {
'hidden': 'teardown',
"click [type='submit']": "notify"
},
initialize: function() {
_.bindAll(this, "show", "teardown", "render", "notify");
this.render();
this.show();
},
show: function() {
this.$el.modal('show');
},
teardown: function() {
this.$el.data('modal', null);
this.remove();
},
render: function() {
this.$el.empty();
this.setElement(this.template(this.model.toJSON()));
},
notify: function() {
var self = this;
this.model.set({
type: self.$el.find("[type='radio']:checked").data("type"),
start: self.$el.find("[name='start']").val(),
end: self.$el.find("[name='end']").val(),
details: self.$el.find("textarea").text()
});
}
});
var InformationModel = Backbone.Model.extend({
id: -1,
defaults: {
type: " ",
title: " ",
start: 2015,
end: 2016,
details: " "
}
});
var InformationView = Backbone.View.extend({
events: {
"click [data-action='modify']": "modifyInformation",
"click [data-action='delete']": "deleteInformation"
},
template: _.template($("#info-row").html()),
initialize: function() {
_.bindAll(this, "render", "modifyInformation", "deleteInformation");
this.render();
},
render: function() {
this.setElement(this.template(this.model.toJSON()));
},
modifyInformation: function() {
var self = this;
modalView = new baseModalView({
model: self.model,
template: _.template($("#info-modify").html())
});
},
deleteInformation: function() {
this.model.destroy();
}
})
var InformationCollection = Backbone.Collection.extend({
url: "../dummy/",
model: InformationModel
});
var InformationsView = Backbone.View.extend({
el: $("#informations"),
initialize: function() {
_.bindAll(this, "render", "addInformation");
var self = this;
this.collection = new InformationCollection();
this.collection.bind("all", this.render, this);
this.collection.fetch();
// I know this is not a Backbone way...
$("#addInformation").on("click", function() {
self.addInformation();
});
},
render: function() {
this.$el.empty();
this.collection.each(function(information) {
var informationView = new InformationView({
model: information
});
this.$el.append(informationView.el);
}, this);
},
addInformation: function() {
var self = this;
modalView = new baseModalView({
model: new InformationModel()
});
}
});
new InformationsView();
$("form").submit(function(e) {
e.preventDefault();
return false;
});
});
</script>
</html>
Question:
After I edit a table row and click on submit, Backbone send a strange GET request.

The form is being submitted when you press the submit button.
This code
$("form").submit(function(e) {
e.preventDefault();
return false;
});
Won't actually stop this from happening, as when this code is executed, the form doesn't yet exist in the dom. It's only added when you create that modal view.
This is not tested, but a quick fix should be to:
$(document).on("submit", "form", function(e) {
e.preventDefault();
return false;
});
This will respond to all "submit" events on the page, and then check if they belong to a "form" element before processing the function.
Another solution, which I think is preferable as all functionality is encapsulated in your view, is to replace the submit button with a regular button in the modal template.
<button type="button" class="btn btn-success">Submit</button>
This should stop the submit event from firing, but you'll need to change the action handler the top of the baseModalView view.

If you have a form in a Backbone view, handle the form in that view, without global jQuery events.
Say you have this simple view template:
<div id="test-view">
<form id="test-form">
<input type="text" name="test">
<button type="submit">Submit</button>
</form>
</div>
Then the view only needs to catch the submit for its form:
var FormView = Backbone.View.extend({
events: {
"submit #test-form": "onSubmit"
},
onSubmit: function(e) {
e.preventDefault();
console.log("test-form submit prevented");
}
});
var view = new FormView({
el: $('#test-view')
});

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:

Load DataTable data to a Edit Modal

I am trying to create an edit function for my data table. The data table is created using Yajra Data tables. Everything working fine unless when I try to load existing data into the edit modal it fails. No error is showing but the modal does not launch. I have only included a little portion of my code here for easy reference.
Modal:
<!-- Update Status Model Box -->
<div id="updateStatusModal" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content bg-default">
<div class="modal-body">
<form class="form-horizontal" id="updateStatus">
#csrf
#method('PUT')
<div class="row">
<div class="col">
<div class="form-group text-center">
<h6 class="font-weight-bold">Stage 1</h6>
<label for="stage_1" class="switch">
<input type="checkbox" class="form-control" id="stage_1">
<div class="slider round"></div>
</label>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="form-group">
<div class="col-md">
<label for="firstname">Coding</label>
<input type="text" class="form-control" id="first_name" value="" placeholder="Enter Completed Page Count">
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer justify-content-between">
<button type="button" name="update_btn" id="update_btn" class="btn btn-outline-warning">Update</button>
</div>
</div>
</div>
</div>
jquery funtion:
// Edit action
$(document).on('click', '.updateStatus', function(){
$tr = $(this).closest('tr');
var data = $tr.clidren("td").map(function(){
return $(this).text();
}).get();
console.log(data);
$('#id').val(data[0]);
$('#job_id').val(data[2]);
$('#stage_1').val(data[3]);
$('#conversion').val(data[4]);
$('#updateStatusModal').modal('show');
});
I tried this method I found but this is not working. Can anyone provide me any pointers here?
I've just didn't seen your front scripts (also back-end codes), but instead I can share my implementation for that you need. It works perfectly like showed in this (screenshot).
Here I'll put front and back codes. There is functionality for editing existsing Datatable record, also record deletion.
FRONT
<!--HERE ATTACH NECESSARY STYLES-->
<!--VIEW end-->
<link rel="stylesheet" type="text/css" href="{{ asset('css/admin/datatables.min.css') }}"/>
<table id="yajra_datatable" class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Options</th>
</tr>
</thead>
</table>
<div class="modal modal-danger fade" id="modal_delete">
<div class="modal-dialog">
<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>
<h4 class="modal-title">Delete Language</h4>
</div>
<div class="modal-body">
<p>Are You sure You want to delete this Language?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline pull-left" data-dismiss="modal">Cancel</button>
<button id="delete_action" type="button" class="btn btn-outline">Submit</button>
</div>
</div>
</div>
</div>
<div class="modal modal-warning fade" id="modal_edit">
<div class="modal-dialog">
<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>
<h4 class="modal-title">Edit Language</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="language_name">Language Name</label>
<input name="language_name" id="language_name" type="text" value="" class="form-control" placeholder="Language Name">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline pull-left" data-dismiss="modal">Cancel</button>
<button id="edit_action" type="button" class="btn btn-outline">Submit</button>
</div>
</div>
</div>
</div>
<input type="hidden" id="item_id" value="0" />
<!--VIEW end-->
<!--HERE ATTACH NECESSARY SCRIPTS-->
<!--SCRIPTS start-->
<script src="{{ asset('js/admin/jquery.dataTables.min.js') }}"></script>
<script type="text/javascript">
var YajraDataTable;
function delete_action(item_id){
$('#item_id').val(item_id);
}
function edit_action(this_el, item_id){
$('#item_id').val(item_id);
var tr_el = this_el.closest('tr');
var row = YajraDataTable.row(tr_el);
var row_data = row.data();
$('#language_name').val(row_data.name);
}
function initDataTable() {
YajraDataTable = $('#yajra_datatable').DataTable({
"processing": true,
"serverSide": true,
"ajax": "{{ route('admin.book_languages.ajax') }}",
"columns":[
{
"data": "name",
"name": "name",
},
{
"data": "",
"name": ""
},
],
"autoWidth": false,
'columnDefs': [
{
'targets': -1,
'defaultContent': '-',
'searchable': false,
'orderable': false,
'width': '10%',
'className': 'dt-body-center',
'render': function (data, type, full_row, meta){
return '<div style="display:block">' +
'<button onclick="delete_action(' + full_row.id + ')" type="button" class="delete_action btn btn-danger btn-xs" data-toggle="modal" data-target="#modal_delete" style="margin:3px"><i class="fa fa-remove"></i> Delete</button>' +
'<button onclick="edit_action(this, ' + full_row.id + ')" type="button" class="edit_action btn btn-warning btn-xs" data-toggle="modal" data-target="#modal_edit" style="margin:3px"><i class="fa fa-edit"></i> Edit</button>' +
'</div>';
}
}
],
});
return YajraDataTable;
}
$(document).ready(function() {
var YajraDataTable = initDataTable();
$('#delete_action').on('click', function (e) {
e.preventDefault();
$.ajax({
url: "{{ route('admin.book_languages.delete') }}",
data: {
'item_id': $('#item_id').val(),
'_token': "{{ csrf_token() }}"
},
type: "POST",
success: function (data) {
$('#modal_delete').modal('hide');
YajraDataTable.ajax.reload(null, false);
console.log(data.message);
}
})
});
$('#edit_action').on('click', function (e) {
e.preventDefault();
$.ajax({
url: "{{ route('admin.book_languages.edit') }}",
data: {
'item_id': $('#item_id').val(),
'language_name': $('#language_name').val(),
'_token': "{{ csrf_token() }}"
},
type: "POST",
success: function (response) {
$('#modal_edit').modal('hide');
YajraDataTable.ajax.reload(null, false);
console.log(data.message);
}
})
});
$('#modal_delete').on('hidden.bs.modal', function () {
$('#item_id').val(0);
});
$('#modal_edit').on('hidden.bs.modal', function () {
$('#item_id').val(0);
$('#language_name').val("");
});
});
</script>
<!--SCRIPTS end-->
BACK
public function index() {
return view('admin.book-languages.index');
}
public function ajax() {
$items = BookLanguage::latest('id');
return DataTables::of($items)->make(true);
}
public function delete(Request $request) {
$item_id = $request->get('item_id');
$item = BookLanguage::find($item_id);
if(empty($item)) {
return response()->json([
'success' => false,
'message' => 'Item not found!',
], 200); // 404
} else {
$item->delete();
return response()->json([
'success' => true,
'message' => 'Item successfully deleted.',
], 200);
}
}
public function update(Request $request) {
$item_id = $request->get('item_id');
$item = BookLanguage::find($item_id);
if(empty($item)) {
return response()->json([
'success' => false,
'message' => 'Item not found!',
], 404);
} else {
$item->name = $request->get('language_name');
$item->save();
return response()->json([
'success' => true,
'message' => 'Item successfully updated.',
], 200);
}
}
ROUTES
// ...
// book_languages
Route::group(['prefix' => 'book-languages', 'as' => 'admin.book_languages.',], function () {
Route::get('all', 'BookLanguageController#index')->name('index');
Route::get('ajax', 'BookLanguageController#ajax')->name('ajax');
Route::post('update', 'BookLanguageController#update')->name('edit');
Route::post('delete', 'BookLanguageController#delete')->name('delete');
});
// ...
I think this can help you and others to build wanted functionality. Here this could be also with more hint-comments, but as it not small, I can answer later via post comments.
i am building a Laravel ERP-like web application and am implementing a CRUD function modal like you. I have made mine a server-side processing application with resource APIs in Laravel. Well, please be reminded that i have cut the #extends(layout.app) & #section('stylesheet') parts to go right into the answer. You should extend them in your own application to make everything work.
View.blade script
<script>
$(document).ready(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var table = $('#customertable').DataTable({
processing: true,
serverSide: true,
dom: 'B<"top"frli>tp',
ajax: {
url: "{{ route('customer.index') }}", //Accessing server for data
columns: [
{data: 'id'}, //data refers to DB column name
{data: 'name'},
{data: 'chiname'},
{data: 'type'},
{data: 'action'}, //this is an addColumn item from Controller
]
});
$('#createNewcustomer').click(function () {
$('#saveBtn').val("create customer");
$('#customerid').val('');
$('#customerForm').trigger("reset");
$('#modelHeading').html("Create New Customer");
$('#customermodal').modal('show');
});
//Control the modal behavior when clicking the edit button.
$('body').on('click', '.editcustomer', function () {
var customerid = $(this).data('id');
$.get("{{ route('customer.index') }}" +'/' + customerid +'/edit', function (data) {
$('#modelHeading').html("Edit Customer");
$('#saveBtn').val("edit-user");
$('#customermodal').modal('show');
$('#customerid').val(data.id);
$('#name').val(data.name);
$('#chiname').val(data.chiname);
$('#type').val(data.type);
})
});
//Create a brand-new record
$('#createNewcustomer').click(function () {
$('#saveBtn').val("create customer");
$('#customerid').val('');
$('#customerForm').trigger("reset");
$('#modelHeading').html("Create New Customer");
$('#customermodal').modal('show');
});
//Update
$('body').on('click', '.editcustomer', function () {
var customerid = $(this).data('id');
$.get("{{ route('customer.index') }}" +'/' + customerid +'/edit', function (data) {
$('#modelHeading').html("Edit Customer");
$('#saveBtn').val("edit-user");
$('#customermodal').modal('show');
$('#customerid').val(data.id);
$('#name').val(data.name);
$('#chiname').val(data.chiname);
$('#type').val(data.type);
})
});
//Save
$('#saveBtn').click(function (e) {
e.preventDefault();
$(this).html('Sending..');
$.ajax({
data: $('#customerForm').serialize(),
url: "{{ route('customer.store') }}",
type: "POST",
dataType: 'json',
success: function (data) {
$('#customerForm').trigger("reset");
$('#customermodal').modal('hide');
table.draw();
},
error: function (data) {
console.log('Error:', data);
$('#saveBtn').html('Error');}
});
});
//Delete
$('body').on('click', '.deletecustomer', function () {
var id = $(this).data("id");
confirm("Are You sure?");
$.ajax({
type: "DELETE",
url: "{{ route('customer.store') }}"+'/'+id,
success: function (data) {
table.draw();
},
error: function (data) {
console.log('Error:', data);
}
});
});
</script>
View.blade html-table & modal part
#section('content')
<div class="container">
<div class="card-header border-left"><h3><strong> Customer overview</strong></h3></div>
<br>
<div class="row">
<div class="col-md text-right">
<button type="button" class="btn btn-success" data-toggle="modal" href="javascript:void(0)" id="createNewcustomer">Create Record</button>
</div>
</div>
{{-- Modal --}}
<div id="customermodal" class="modal fade" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="modelHeading"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times</span></button></div>
<div class="modal-body">
<form id="customerForm" name="customerForm" class="form-horizontal">
<input type="hidden" name="customerid" id="customerid">
<div class="form-group">
<label for="name" class="col-sm-6 control-label">Customer Name</label>
<div class="col-sm-12">
<input type="text" class="form-control" id="name" name="name" placeholder="Name" value="" maxlength="50" required="">
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">Customer Name</label>
<div class="col-sm-12">
<input type="text" class="form-control" id="chiname" name="chiname" placeholder="Customer Name" value="" maxlength="50" required="">
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">Contract type</label>
<div class="col-sm-12">
<select name="type" id="type" class="form-control">
<option value="" disabled>Type</option>
<option value="Government">Government Contract</option>
<option value="Private">Private Contract</option>
</select>
</div></div>
<br>
<div class="col-sm text-right">
<button type="submit" class="btn btn-outline-secondary" id="saveBtn" value="create">Save changes</button>
</div>
</form>
</div>
</div>
</div>
</div>
{{-- Table --}}
<br>
<div class="row">
<br/>
<br/>
<div class="form-group col-md-12 align-content-center">
<table class="table-fluid center-block" id="customertable">
<thead>
<tr>
<th>id</th>
<th>ChiName</th>
<th>Name</th>
<th>Type</th>
<th>Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
#endsection
CustomerController
public function index(Request $request)
{
$customers = Customer::all();
}
return Datatables::of($customers)
->addColumn('action', function($customer){
$btn = 'Edit';
$btn = $btn.' Delete';
return $btn;})
->rawColumns(['action'])
->make(true);
}
return view('customer.Customer'); //my view blade is named Customer under customer dir. put your blade destination here.
}
public function store(Request $request)
{
Customer::updateOrCreate(['id' => $request->customerid],
['name' => $request->name, 'chiname' => $request->chiname,'type' =>$request->type]);
return response()->json(['success'=>'Product saved successfully.']);
}
public function edit($id)
{
$customer = Customer::findorfail($id);
return response()->json($customer);
}
public function destroy($id)
{
Customer::findorfail($id)->delete();
return response()->json(['success'=>'Product deleted successfully.']);
}
Model (pick either A.) $guarded = [] OR B.) $fillable = ['fields','fields'] as you like)
class Customer extends Model
{
protected $fillable = ['name','chiname','type'];
}
web.api (route setting)
Route::resource('customer', 'CustomerController')->middleware('auth');
Migration / DB schema structure
class CreateCustomersTable extends Migration
{
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('chiname');
$table->string('type');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('customers');
}
I have not included any protection in it like gate, auth or so. But basically this is the skeleton of doing CRUD with dataTable in Laravel framework with both JS, Ajax, Jquery, PHP all in one. Kindly be reminded that the queries for such CRUD actions are directly linked to the Database server. If you want to show data processed by the DataTable, use your own jquery function to fetch and show them on the modal. My answer is not the best but i hope it helps you >:)
(I could not post a picture to show you here as i dont have enough reputation lol. gg)

Pass the view that manages something to the second view - Backbone

I have two views, one for rendering google maps and another to render list of events that contain's latitude and longitude to render markers on the view that contains google maps. When I try to pass the view that manages the map to the initialize method of the second view and save an instance reference, display in console the following error:
Here's my code
app.js
var ev = new Application();
ev.Router = Backbone.Router.extend({
routes: {
"": "home",
"evento/:id" : "evento"
},
home: function(){
var mapView = new ev.views.Home();
$('#home').html(mapView.el);
$('#rightcolumn').html(new ev.views.Home_Eventos(mapView).el);
},
evento: function(id){
$('#rightcolumn').html(new ev.views.Evento(id).el);
}
});
$(document).on('ready', function() {
// Load HTML templates for the app
ev.templateLoader.load(['shell', 'home', 'home_list_eventos', 'evento'], function () {
ev.shell = new ev.views.Shell({el: "#shell"});
ev.router = new ev.Router();
Backbone.history.start();
});
});
home.js
ev.views.Home = Backbone.View.extend({
map: 'null',
initialize: function(){
this.template = _.template(ev.templateLoader.get('home'));
this.render();
},
initMap: function(){
var that = this;
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos;
pos = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
var infowindow = new google.maps.InfoWindow({
map: that.map,
position: pos
});
that.map.setCenter(pos);
});
}
var mapOptions = {
zoom: 12,
};
that.map = new google.maps.Map(that.$el.find('#map_canvas')[0],mapOptions);
google.maps.event.addDomListener(window, "resize", function() {
var center = that.map.getCenter();
google.maps.event.trigger(that.map, "resize");
that.map.setCenter(center);
});
},
render: function(){
this.$el.html(this.template());
this.initMap();
return this;
}
});
home_events.js
ev.views.Home_Eventos = Backbone.View.extend({
initialize: function(mapView){
this.template = _.template(ev.templateLoader.get('home_list_eventos'));
this.mapView = mapView;
console.log(this.mapView.map);
this.render();
console.log("sou inicializado");
},
render: function(){
var that = this;
var imagens = new ev.models.ImagemCollection();
imagens.fetch({
success: function(){
that.$el.html(that.template({imagens: imagens.models}));
var marcadores = imagens.models;
setTimeout(function() {
_.each(marcadores, function(marcador){
var myLatlng = new google.maps.LatLng(marcador.get('latitude'),marcador.get('longitude'));
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
});
});
}, 6000);
return that;
}
});
}
});
Templates of document:
shell.html:
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
...
</nav>
<div class="wrapper-home" id="home">
</div><!--/.fluid-container-->
home.html:
<div id="leftcolumn">
<div id="map_canvas"></div>
</div>
<div id="rightcolumn">
<div class="row">
<div class="col-xs-5 coluna-input">
<form role="form">
<div class="form-group">
<label for="pesquisar">Pesquise</label>
<input type="text" class="form-control" id="pesquisar" placeholder="Pesquisar...">
</div>
<div class="form-group">
<label for="quando">Quando</label>
<input type="text" class="form-control" id="quando" placeholder="Quando">
</div>
</form>
</div>
<div class="col-xs-5 coluna-input">
<form role="form">
<div class="form-group">
<label for="pac-input">Onde</label>
<input type="text" class="form-control" id="pac-input" placeholder="Onde">
</div>
<div class="form-group">
<label for="genero">Género</label>
<input type="text" class="form-control" id="genero" placeholder="Genero">
</div>
</form>
</div>
<div class="col-xs-5 coluna-input">
<button id="search" type="button" class="btn btn-primary botao">Pesquisar</button>
</div>
<div class="col-xs-5 coluna-input">
<button type="button" class="btn btn-danger botao">Mais Filtros</button>
</div>
</div>
<hr class="linha"/>
<div class="row" id="lista">
<div class="table">
<tbody>
<% _.each(imagens, function(imagem){ %>
<tr>
<div class="col-xs-5 coluna-input">
<img src="<%= imagem.get('imagem') %>" class="img-responsive back" alt="Responsive image">
Ver Mais
</div>
</tr>
<% }); %>
</tbody>
</div>
</div>
</div>
You initialize new ev.views.Home_Eventos(mapView) as a parameter to $.html(), which is fine except that the render function in that view is 'async' because of the fetch in it. So the el it returns should be an empty <div> since the success callback doesn't return until after the initialize is complete.

Action isn't call functions on view, from template - Ember

SO basically I create a view like so (I create it like this as I need it to act as a pop up)
Application.container = Ember.ContainerView.create();
Application.container.append();
Application.loginOverlay = Application.LoginOverlayView.create({
});
Application.childViews = Application.container.get('childViews');
Application.childViews.pushObject(Application.loginOverlay);
I have a view that looks like this
Application.LoginOverlayView = Ember.View.extend({
templateName: 'view/loginOverlay',
password: null,
logBackIn: function (password) {
console.log('logBackIn');
},
closeOverlay: function () {
console.log('closeOverlay');
},
username: function () {
return Application.user.get('username');
}.property().volatile()
});
Here's my template
<div id="login-overlay" class="overlay">
<section>
<form id="login_form">
<div class="control-group">
<label class="control-label" for="username">{{localise _username}}: {{username}}</label>
</div>
<div class="control-group">
<label class="control-label" for="reenter-password">{{localise _password}}</label>
<div class="controls">
{{view Ember.TextField name="reenter-password" elementId="reenter-password" valueBinding="password" placeholder="password" type="password"}}
</div>
</div>
<div class="control-group">
<input type="button" value="{{localise _login}}" class="btn btn-success" {{action 'logBackIn' password target="view"}} {{bindAttr disabled=busy}} />
<input type="button" value="{{localise _cancel}}" class="btn btn-danger" {{action 'closeOverlay' target="view"}} {{bindAttr disabled=busy}} />
</div>
</form>
</section>
</div>
The actions on the view are doing anything when clicked.
I'm using an old verion of Ember - v1.0.0-rc.7-9-g7398406
Any ideas?
*EDIT*
I did try it with the actions hash like so
Application.LoginOverlayView = Ember.View.extend({
// layoutName: 'view/loginOverlay',
templateName: 'view/loginOverlay',
password: null,
init: function () {
console.log('LoginOverlayView');
this._super();
},
actions: {
logBackIn: function (password) {
console.log('logBackIn');
},
closeOverlay: function () {
console.log('closeOverlay');
Application.removePasswordOverlay();
},
username: function () {
console.log('username');
return Application.user.get('username');
}.property().volatile()
}
});
but no joy. Also I added the init to make sure it was being created and it was, the log is being called
Another thing to add is that I'm not getting any feedback when I click the buttons. I'm not getting any kind of error or anything.

$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