I'm using BS-3 and bs-confirmation https://github.com/tavicu/bs-confirmation.
I have a button in my html which I click on, it display yes or no and then I can click on yes or no button
<a data-href="/api/yes-no/" class="btn" data-toggle="confirmation">Confirmation</a>
and javascript
<script type="text/javascript">
$(function() {
$('body').confirmation({
selector: '[data-toggle="confirmation"]',
btnOkLabel: 'Yes',
btnCancelLabel: 'No',
btnOkClass: "btn btn-sm btn-success",
btnCancelClass: "btn btn-sm btn-danger"
});
$('.confirmation-callback').confirmation({
onConfirm: function() { console.log('YES') },
onCancel: function() { console.log('NO') }
});
});
</script>
I want to send yes or no(whichever user click on) to my API (/api/yes-no/) using POST method.
but when I click on yes/no it open the api page(I mean GET request) how can I make it POST with form field ({'type': 'YES' or 'No' or anyother boolean})
onConfirm function is attached to the element you are initially clicking on, so you can use it to get data-href and then use standard jQuery method to invoke POST request.
<script type="text/javascript">
$(function() {
$('body').confirmation({
selector: '[data-toggle="confirmation"]',
btnOkLabel: 'Yes',
btnCancelLabel: 'No',
btnOkClass: "btn btn-sm btn-success",
btnCancelClass: "btn btn-sm btn-danger",
onConfirm: function () {
$.post(
$(this).attr('data-href'),
{}, // you data for POST body
function (data) {
// act on the response
}
);
}
});
});
</script>
Related
I have a Vue 'app' of sorts. It's just part of a larger Django application - but I'm using this to springboard my Vue learning.
I'm trying to create unique forms that would be editable.
I have been messing about with this for a while trying to figure out how to 'disable all the forms except the one being edited'.
If a new 'evidence' is added, that form should be enabled and the others uneditable.
If an existing evidence is being edited then the 'add evidence' button should not be active and only the form being edited should be able to be edited.
My Vue looks like this - I have a base container (that's the Vue app) and a component (that is the forms):
var evidenceFormComponent = Vue.component("evidence-form", {
template: "#evidenceFormTemplate",
props: ["csrf_token", "evaluation_id", "element"],
components: {},
data: function () {
console.log("data function");
return {
evidence: getEvidence(),
subdomains: getSubdomains(),
isDisabled: null,
baseUrl: null
};
},
created: function () {
console.log("created_function!");
this.baseUrl = "/api/";
this.subdomainUrl = "/api/";
this.fetchAdditionalEvidence();
this.fetchSubdomainList();
this.isDisabled = true;
},
methods: {
fetchSubdomainList: function () {
// get the evidence if any using a Jquery ajax call
console.log("this should be fetching the subdomains");
return getSubdomains;
},
fetchAdditionalEvidence: function () {
// get the evidence if any using a Jquery ajax call
console.log("this is fetching additional evidence");
return getEvidence();
},
editForm: function (element) {
console.log("editing the form!");
this.isDisabled=false;
},
cancelEdit: function () {
console.log("cancel the edit!");
}
}
// watch:
});
const vm = new Vue({
el: "#evidenceFormsContainer",
data: function () {
console.log("parent data function");
return {
evidence: getEvidence(),
subdomains: getSubdomains(),
isDisabled: false,
baseUrl: null
};
},
methods: {
addForm: function () {
console.log("adding a child form!");
this.evidence.unshift({});
},
}
});
getEvidence and getSubdomains just return generic stuff atm as I would expect from an API.
I have read that it is best to have all UI elements present in case someone has JS disabled or something odd. So I figured I would create all 4 buttons then show/hide depending on if they should be disabled or not.
<button class="btn btn-primary text-white valign-button" v-on:click.prevent="element.isDisabled=false" #click="editForm()">
<i class="far fa-edit"></i> EDIT
</button>
<button :id="'saveButton'+element.id" v-if="element.isDisabled" v-on:click.prevent="element.removedRow=true" class="btn btn-primary text-white valign-button">
<i class="far fa-save"></i> SAVE
</button>
<button class="btn bg-danger text-white valign-button" data-toggle="modal" data-target="#deleteEvidenceModal" v-on:click.prevent>
<i class="fal fa-trash-alt"></i> DELETE
</button>
<button v-if="element.isDisabled" v-on:click.prevent="element.removedRow=true" class="btn bg-secondary text-white valign-button" #click="cancelEdit()">
<i class="fas fa-minus"></i> CANCEL
</button>
The problem I am running into is figuring how to tell if I'm editing one, or if it is a new one being added and properly disabling all the other elements.
For clarity I have made a JSFiddle of this in practice.
When you click 'add evidence' in the example, you will see. The form is 'disabled' still and the other forms still have the ability to click 'edit'.
I'm a bit lost. Would a child component for the buttons be better? Then if I'm editing a form or creating a new one, I can hide all the buttons on all the other instances?
All advice welcome!
Create a global reference to an activeForm element:
data: function () {
console.log("data function");
return {
evidence: getEvidence(),
subdomains: getSubdomains(),
isDisabled: null,
baseUrl: null,
activeForm: null // this is what we're adding
};
},
When you're in a loop, you know the index of the element you're working with. Pass that to your function:
#click="editForm(index)"
Assign that index to your activeForm variable:
editForm (index) {
this.activeForm = index
}
Change your v-if comparator assignment to observe whether the current index is the same as the activeForm:
v-if="activeForm && activeForm === index
In this way, a single variable is responsible for determining the edit state.
If you want to disable all the forms when adding, I'd just make another variable called adding and set it to true/false in the same way we did above with the other functions, and modify the v-if on the edit and delete buttons:
v-if="(activeForm && activeForm === index) && !adding"
When I click the save button to save my controller function is firing twice. What is the problem in my code I don't know. Please help me.
Here is my button click to call ajax and save values.
<button id="btnSave" type="submit" title="Save" class="btn btn-success" onclick="getPage('#(Url.Action("Save", "Carriers"))')">
<span class="glyphicon glyphicon-floppy-disk"></span>Save
</button>
Here is my ajax
$.ajax({
type: "POST",
url: page,
data: $("#frmEdit").serialize(),
xhrFields: {
withCredentials: true
},
success: function (html) {
$('#CarrierList').empty();
$('#CarrierList').append($.parseHTML(html));
},
error: function () {
var error = "Error occured during loading Carrier items...";
$('#errorMessage').empty();
$('#errorMessage').append(error);
$('#errorModal').modal('show');
},
complete: function () {
$('#loaderImg').modal('hide');
}
});
}
Here is my controller method
public override ActionResult Save(CarrierDTO carrierDTO)
{
string[] ErrorMessageArray = new string[4];
int errorIndex = 0;
if (ModelState.IsValid)
{
MessageCollection messages = new MessageCollection();
carrierDTO.Save(ref messages);
if (messages.IsErrorOccured() || messages.IsExceptionOccured())
{
ModelState.AddModelError("", messages[0].Text);
return View("Edit", carrierDTO);
}
return View("Edit", carrierDTO);
}
You need to add 'preventDefault()'.
If the prevent default method is called, the default action of the event will not be
triggered.
In your case, the prevent default will stop submitting the form(the default action of the submit button), and use the ajax snippet to do so instead.
JQ:
$(function(e){
e.preventDefault();
$.ajax({
type: "POST",
url: page,
data: $("#frmEdit").serialize(),
xhrFields: {
withCredentials: true
},
success: function (html) {
$('#CarrierList').empty();
$('#CarrierList').append($.parseHTML(html));
},
error: function () {
var error = "Error occured during loading Carrier items...";
$('#errorMessage').empty();
$('#errorMessage').append(error);
$('#errorModal').modal('show');
},
complete: function () {
$('#loaderImg').modal('hide');
}
});
}
});
Two solutions
Use type="button" in your button control
<button id="btnSave" type="button" title="Save" class="btn btn-success" onclick="getPage('#(Url.Action("Save", "Carriers"))')">
<span class="glyphicon glyphicon-floppy-disk"></span>Save
</button>
or remove onclick="getPage('#(Url.Action("Save", "Carriers"))'), because the submit button take a post action in default .
<button id="btnSave" type="submit" title="Save" class="btn btn-success" ">
<span class="glyphicon glyphicon-floppy-disk"></span>Save
</button>
In you App_Start folder open the BudleConfig.cs file and do few changes:
First take a look to this line (this is an original VS generated content).
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));
Note that '...validate*' pattern will load five scripts from your Scripts folder (this is true for my case):
~/Scripts/jquery.validate-vsdoc.js
~/Scripts/jquery.validate.js
~/Scripts/jquery.validate.min.js
~/Scripts/jquery.validate.unobtrusive.js
~/Scripts/jquery.validate.unobtrusive.min.js
As you can see, you are loading the unobtrusive.js twice (jquery.validate.unobtrusive.js and jquery.validate.unobtrusive.min.js). So, make your own code something like this to exclude, say full version js:
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate-vsdoc.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate.min.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate.unobtrusive.min.js"));
or make some mechanism to load full or min versions per your desire.
I have the following script which is rendering a partial view inside a dialog box:
$(function () {
$('#addressLookupBtn').click(function () {
$('#dialog').dialog({
title: 'Address Lookup Tool',
modal: true,
width: '1200',
height: 'auto',
resizable: false,
show: {
effect: "fade",
duration: 2000
},
hide: {
effect: "fade",
duration: 1000
},
open: function (event, ui) {
//Load the AddressLookup action which will return
//the partial view: _AddressLookup
$(this).load("#Url.Action("AddressLookup", new { evpId = Model.EvpId })");
}
}).dialog('open');
});
});
The problem is, when I submit the partial view, there are 2 POSTS being made to the server, I think the submit for the partial view is also being bound to the $('#addressLookupBtn').click. Can anyone see where I'm going wrong?
more info
Partial view
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "updatearea" }))
{
<div id="updatearea" class="form-group">
<div style="width:300px; display:block; float:left;">
#Html.TextBox("PostCode", null, new { #class = "form-control" })
</div>
<div id="NewAddressLine">
<input type="submit" value="Lookup Postcode" class="btn btn-default" />
</div>
</div>
}
It looks like the post is being submitted using both a normal form submit and as a jquery event.
Perhaps change it to a button (instead of submit) and use only the jquery submit, or remove the jquery event and use only the normal form submit.
As per comments - An example of using jquery ajax instead of MS ajax:
The script:
$(document).ready(function() {
event.preventDefault(); // stop the form from submitting the normal way
$('#MyForm').submit(function(event) {
$.post(
$('#MyForm').attr('action'),
{ 'PostCode' : $('input[name=PostCode]').val() }
)
.done(function(data) {
alert('Post worked, and data was returned. Parse and/or present.');
$('#updatearea').html(data); //Replace the current contents of "updatearea" with the returned contents
});
});
});
The PartialView:
#using (Html.BeginForm("MyAction", "MyController", new { #id = "MyForm" }))
{
<div id="updatearea" class="form-group">
<div style="width:300px; display:block; float:left;">
#Html.TextBox("PostCode", null, new { #class = "form-control" })
</div>
<div id="NewAddressLine">
<input type="submit" value="Lookup Postcode" class="btn btn-default" />
</div>
</div>
}
It looks like you are calling open, and still have autoOpen set to true (it is true by default). This is causing open event to run twice. Try setting autoOpen to false
$('#dialog').dialog({
...
autoOpen: false,
...
});
https://api.jqueryui.com/dialog/#option-autoOpen
It turns out I didn't need to change anything other than move the following bundle reference from _Layout to my Edit view:
#Scripts.Render("~/bundles/unobtrusive-ajax")
I am fairly new to AngularJS and having a problem with returning data from a modal dialog service. Basically, I copied Dan Wahlin's service http://weblogs.asp.net/dwahlin/archive/2013/09/18/building-an-angularjs-modal-service.aspx and am calling it from my controller.
myApp.controller('MyController', function($scope, ModalService) {
window.scope = $scope;
$scope.mydata = {name: ""};
$scope.showModal = function () {
var modalOptions = {
closeButtonText: 'Cancel',
actionButtonText: 'Save',
headerText: 'Save Dialog'
}
ModalService.showModal({}, modalOptions).then(function (result) {
});
}
});
Then I have my partial like so:
<div class="modal-header">
<h3>{{modalOptions.headerText}}</h3>
</div>
<form ng-submit="modalOptions.submit()">
<div class="modal-body">
<label>Name</label>
<input type="text" data-ng-model="mydata.name">
</div>
<div class="modal-footer">
<button type="button" class="btn" data-ng-click="modalOptions.close()">{{modalOptions.closeButtonText}}</button>
<button type="submit" class="btn btn-primary">{{modalOptions.actionButtonText}}</button>
</div>
This modal is being invoked like this:
<button class="btn btn-primary hidden pull-right" id="save" data-ng-click="showModal()">Save</button>
So my question is how do I get the value of the name field back to the controller? I've looked all over the web and all the examples have the function that opens the modal reside inside the controller, which makes it much easier as $scope from the controller also exists in the function that opens the modal.
I tried adding the following code to the 'show' function in the service but it did not work.
tempModalDefaults.resolve = function($scope) {
mydata = function () {
return $scope.mydata;
}
}
Thanks
P.S. I renamed modalService to ModalService in my code, so that's not a typo. The modal opens and closes as it should, I just can't pass the field's value back to the controller.
In your button, add data-ng-click="modalOptions.ok(mydata)"
<button type="submit" class="btn btn-primary" data-ng-click="modalOptions.ok(mydata)">{{modalOptions.actionButtonText}}</button>
And you can get it from:
ModalService.showModal({}, modalOptions).then(function (result) {
console.log(result.name);
});
DEMO
If you want to use modalOptions.submit function, you need to change your code a bit
In your HTML, pass the mydata to modalOptions.submit function:
<form ng-submit="modalOptions.submit(mydata)">
Your Model Service, replace in the show function:
return $modal.open(tempModalDefaults); //remove the .result
Your controller:
$scope.showModal = function () {
var modalOptions = {
closeButtonText: 'Cancel',
actionButtonText: 'Save',
headerText: 'Save Dialog',
submit:function(result){
$modalInstance.close(result);
}
}
var $modalInstance = ModalService.showModal({}, modalOptions);
$modalInstance.result.then(function (result) {
console.log(result.name);
});
}
DEMO
Here is my code:
<td class="tedit">
<%= Html.ActionLink(item.Comments, "Comments", new { jobNumber = item.JobNumber, ordNumber = item.OrderNumber }, new { #class = "modalEdit" })%>
</td>
<div id="resultEdit" title="Edit Comments" style="display: none;">
<% Html.RenderPartial("AddComments", Model.InnerModel.RoadReportModelProp); %>
</div>
<script type="text/javascript">
$(document).ready(function () {
//initialize the dialog
$("#resultEdit").dialog({ modal: true, width: 300, resizable: true, position: 'center', title: 'Add Comments', autoOpen: false,
buttons: { "Save": function () {
var dlg = $(this);
dlg.Close();
}}
});
});
$(function () {
$('.modalEdit').click(function () {
//load the content from this.href, then turn it into a dialog.
$('#resultEdit').load(this.href).dialog('open');
$.unblockUI();
return false;
});
});
</script>
I need to send a POST request to the controller when I click on the SAVE button in the dialog, but I am not able to send a POST.
Please help.
You should be able to use $.post to save your data. For example
$.post(url, data, function(response) {
// Do something with response
});
You will need to collect the data from the dialog.
Regards,
Huske
<div>
<% using (Html.BeginForm("Post-FormActionName", "Controllername"))
{
%>
<div class="fieldsColumn">
<label>Name: *</label>
<%=Html.TextBoxFor("Name")%>
</div>
<div class="fieldsColumn">
<input id="submit" type="submit" value="Save"/>
</div>
<%}%>
</div>
You can use the following to Post, further, can you provide the code for the form you want to post, & also the controller you have created:
<script type="text/javascript">
$(document).ready(function() {
//get the form
var f = $("#idofForm");
var action = f.attr("action");
var serializedForm = f.serialize();
$.post(action, serializedForm, function() {
alert('we are back');
}
});
</script>