I have a razor page where evrything is displaying fine, but I need to be able to read the values inside a few controllers to pass them as parameters in an call to prefilter some data:
#page
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#model MyApp.Pages.IndexModel
#{
ViewData["Title"] = "MyApp";
}
<div class="col-12 border p-3 mt-3">
<h3>Filters</h3>
<div class="col-12">
<select id="portMultiselect" name="lsPorts" asp-items="#Model.Ports" multiple></select>
<input id="searchString" type="text" name="searchString">
</div>
</div>
#* A "REFRESHABLE" TABLE GOES HERE...*#
#section scripts{
#* REFRESH SCRIPT *#
<script type="text/javascript">
$(function () {
setInterval(loadTable, 60000);
loadTable();
});
function loadTable() {
var select1 = document.getElementById("portMultiselect");
var selectedPorts = [];
for (var i = 0; i < select1.options.length; i++) {
if (select1.options[i].selected) selectedPorts.push(select1.options[i].value);
}
var searchString = document.getElementById('searchString').value;
if (searchString != "" || selectedPorts.length != 0) {
debugger;
}
fetch('/Index?handler=IndexPartial', {
data: {
searchString: searchString,
selectedPorts: selectedPorts
}
})
.then((response) => {
return response.text();
})
.then((result) => {
document.getElementById('refreshable').innerHTML = result;
});
}
</script>
}
As you can see, I'm trying to capture the selected values in my multiselect and in a text input to pass as parameters in the refresh script.
I'm correctly arriving to the expected endpoint, but Im never getting any values (It's always empty and zero) I even added a debugger in the Javascript code that I'm never hitting.
Why can't I read those values?
EDIT:
I have seen other ways of dealing with these, such as databindings, but as mentioned here, the only way to avoid page reload is javascript and AJAX, so I still need to get these values from the javascript.
At the end, I found a solution to my predicament as follows:
I changed the way I render the selectPicker, following the examples shown in this page:
#page
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#model MyApp.Pages.IndexModel
#{
ViewData["Title"] = "MyApp";
}
<div class="col-12 border p-3 mt-3">
<h3>Filtros</h3>
<div class="row">
<div class="col-6">
<p>Puertos</p>
#Html.DropDownListFor(x =>
x.selectPort,
(IEnumerable<SelectListItem>)ViewData["MyPorts"],
new
{
#id = "portMultiselect",
#class = "form-control selectpicker",
#Value = #Model.Ports,
data_live_search = "true",
multiple = "multiple"
})
</div>
<div class="col-6">
<p>Nombre de variable</p>
<input id="searchString" type="text" name="searchString">
</div>
</div>
</div>
This comes with certain changes to the model you're working with, you can follow instructions to bind data as T.Trassoudaine commmented, here
for this to work you need to add the specified references in your _Layout (for the bootstrap-select), you can check all the things you need to add here
And finally, you will need to work with AJAX in javascript to pass the parameters back:
<script type="text/javascript">
$(function () {
setInterval(loadTable, 1000);
loadTable();
});
function loadTable() {
var select1 = document.getElementById("portMultiselect");
var selectedPorts = [];
for (var i = 0; i < select1.options.length; i++) {
if (select1.options[i].selected) selectedPorts.push(select1.options[i].value);
}
var searchString = document.getElementById('searchString').value.toUpperCase();
var searchPorts = "";
if (selectedPorts.length != 0) {
searchPorts = selectedPorts.join(",");
}
$.ajax({
url: '/?handler=IndexPartial',
data: {
searchString: searchString,
searchPorts: searchPorts
},
success: function (data) {
document.getElementById('refreshable').innerHTML = data;
}
})
}
</script>
Related
Hi everyone and thanks for reading this message at first.
I am currently struggling with an ASP.Net MVC Framework project for passing data between views.
I have a controller Model with Index View and a javascript that helps me getting ids of objects clicked on a 3d model rendered in a canvas. Here is the view :
<div class="col-md-10">
<canvas id="viewer"></canvas>
</div>
<div class="col-md-2">
<btn id="AddEventObjects" class="btn btn-eiffage-red">Create a task</btn>
<table id="selectedElements" class="table table-striped">
<thead><tr><th>Selected parts</th></tr></thead>
</table>
</div>
<script type="text/javascript">
var viewer = new xViewer('viewer');
var selectedIds = [];
viewer.on('loaded',
() => {
viewer.start();
});
viewer.on('pick', function (args) {
if (args == null || args.id == null) {
return;
}
var id = args.id;
//If the id was previously clicked then remove it from the list and remove the highlight
if (selectedIds.includes(id)) {
var index = selectedIds.indexOf(id);
selectedIds.splice(index, 1);
} else {
selectedIds.push(id);
}
//Add elements to the table
var table = document.getElementById('selectedElements');
var oldtbody = document.getElementById('selectedElementsBody');
if (oldtbody) {
oldtbody.remove();
}
var tbody = document.createElement('tbody');
tbody.id = "selectedElementsBody";
for (var i = 0; i < selectedIds.length; i++) {
var row = document.createElement('tr');
var cell = document.createElement('td');
cell.textContent = selectedProperties[i];
row.appendChild(cell);
tbody.appendChild(row);
table.appendChild(tbody);
}
});
viewer.load('../Content/3d/Maintenance.wexbim');
</script>
With the script under I would like to open another window passing the selectedIds array :
<script type="text/javascript">
$('#AddEventObjects').click(function () {
$.ajax({
url: "#(Url.Action("AddEventObjects", "Planning"))",
type: "GET",
dataType : "json",
data: { selectedObjects: selectedIds},
cache: false,
async: true,
traditional: true,
success: function (data) {
window.location = "/Planning/AddEventObjects";
},
error: function () {
alert("error");
}
});
});
</script>
Knowing that my controller Planning has an action called AddEventObjects:
public ActionResult AddEventObjects(string[] selectedObjects) {
ViewBag.Title = "Ajout intervention";
var addEventObjectsViewModel = new AddEventObjectsViewModel {
Title = "",
StartTime = "",
EndTime = "",
AllUsers = _context.Users.ToList(),
SelectedUsers = new List<ApplicationUser>(),
PostedUsers = new PostedUsers(),
ObjectsIds = selectedObjects.ToList(),
};
addEventObjectsViewModel.PostedUsers.SelectedIds = addEventObjectsViewModel.SelectedUsers.Select(x => x.Id).ToArray();
return View(addEventObjectsViewModel);
}
I would like it to open the following view that displays the selectedIds :
#model Maintenance.Web.Models.AddEventObjectsViewModel
using (Html.BeginForm("AddEvent", "Planning", FormMethod.Post, new { #class = "form-horizontal", role = "form" })) {
#Html.AntiForgeryToken()
<h4>Créer une nouvelle intervention</h4>
<div class="form-horizontal col-md-12">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-row col-md-12">
<div class="col-md-4">
<div class="form-group">
#Html.LabelFor(m => m.ObjectsIds, htmlAttributes: new { #class = "control-label" })
<table class="table table-striped" style="width:100%; margin-top:20px">
<thead>
<tr>
<th>Id</th>
</tr>
</thead>
#if (Model != null) {
foreach (var objectId in Model.ObjectsIds) {
<tr>
<td>#objectId</td>
</tr>
}
}
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<div class="col-md-10">
<input type="submit" class="btn btn-eiffage-red" value="Ajouter" />
</div>
</div>
</div>
}
With a more basic question : how can I pass an array from a javascript in a view to another view?
Thanks a lot for your help.
If you are passing an array of data, there are a few ways. The easiest of ways is to do the following. Join the array IDS into a comma separated string:
var idList = data.PostedUsers.SelectedIds.join(); //comma sep list
window.location = "/Planning/AddEventObjects?ids=" + idList;
This would work with what you have very simply; it will build a URL like:
/Planning/AddEventObjects?ids=1,2,3,4
In the backend, you have a "string ids" parameter, and split it by comma, and use the IDs however you need to.
Thanks Brian Mains!
I went with passing data in the url as you suggested.
I just used Json serialized data instead of coma separated values :
<a id="CreateEvent" class="btn" href="">Créer une intervention</a>
...
var createLink = "/Planning/AddEventObjects?ids=" + JSON.stringify(model.ids);
$('#CreateEvent').attr("href", createLink);
And then in my controller :
public ActionResult AddEventObjects(string ids) {
if (ids == null) {
return HttpNotFound();
}
string[] objectIds = JsonConvert.DeserializeObject<string[]>(ids);
}
I'm creating a integration with a payment service.
The payment service provides me a form with a script tag inside.
My question is a continuation from Insert a script tag inside template Vue
The form with checkout of payment service:
<form action="http://localhost:8081/api/v1/payment/" method="POST">
<script
src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
data-public-key="KEY"
data-transaction-amount="14.90">
</script>
</form>
I can make the next on "mounted()" of vuejs:
<form ref="myform">
...
</form>
mounted() {
let foo = document.createElement('script');
foo.setAttribute("src","https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
foo.setAttribute("data-transaction-amount", this.newAmount)
this.$refs.myform.appendChild(foo);
}
But, my problem is that after the view has been mounted. the user can change "data-transaction-amount".
To solve it , I tried:
data:()=>({
newAmount:0
})
watch: {
newAmount() {
this.modifyScript();
},
},
methods: {
modifyScript() {
let scripts = document.getElementsByTagName("script");
for (let i = 0; i < scripts.length; i++) {
let script = scripts[i];
if (script.getAttribute("src") == 'https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js') {
// we've got a match
script.setAttribute("data-transaction-amount", this.newAmount);
}
}
},
The "data-transaction-amount" is changing to new value, but the window checkout of payment service shows the original value used in "mounted()".
One solution should be let the browser force to reload the javascript file after the amount is changed.
Below is one steps:
adds one version# into the end of the URL
when amount is changed, removes the script element (src=...?old_amount) already added before
adds new script element (src=...?new_amount)
Below is one fiddle (open the browser console, then you will see the script web-tokenize-checkout.js is redownloaded when the amount is changed).
Vue.component('v-loadjs',{
template:`
<div>
<p><button class="btn btn-info" v-on:click="changeAmount()">Change Amount: {{amount}}</button></p>
<p ref="test"></p>
</div>
`,
data () {
return {
amount: 0,
url: 'https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js'
}
},
mounted: function () {
this.loadJS(this.amount, this.amount)
},
watch: {
amount: function(newAmount, oldAmount) {
this.loadJS(newAmount, oldAmount)
}
},
methods: {
changeAmount: function () {
this.amount += 1
},
loadJS: function (newAmount, oldAmount) {
[...document.querySelectorAll('button.mercadopago-button')].forEach(item => item.remove())
let scripts = document.getElementsByTagName("script");
for (let i = 0; i < scripts.length; i++) {
if (scripts[i].getAttribute("src") == this.url + '?version=' + oldAmount) {
scripts[i].remove()
}
}
let foo = document.createElement('script');
foo.setAttribute("src", this.url + '?version=' + newAmount);
foo.setAttribute("data-transaction-amount", newAmount)
this.$refs.test.appendChild(foo);
}
}
})
new Vue ({
el:'#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div class="container">
<div class="col-lg-offset-4 col-lg-4">
<v-loadjs></v-loadjs>
</div>
</div>
</div>
I have tried javascript and JQuery. I know how to write the code to get the cell values from my first tab but the same function does not work on the other tabs on my webpage. It seems as if the table in my other tabs is just a view. I am new to javascript and JQuery so think I might be missing something easy. I have used ".on" in my click function and that doesn't help. Here is the Javascript code and JQuery code, both work by grabbing the cell value I click but only for the first tab:
JavaScript
init();
function init(){
addRowHandlers('customerTable');
}
function addRowHandlers(tableId) {
if(document.getElementById(tableId)!=null){
var table = document.getElementById(tableId);
var rows = table.getElementsByTagName('tr');
var cid = '';
var name = '';
for ( var i = 1; i < rows.length; i++) {
rows[i].i = i;
rows[i].onclick = function() {
cid = table.rows[this.i].cells[0].innerHTML;
name = table.rows[this.i].cells[1].innerHTML;
alert('cid: '+cid+' name: '+name);
};
}
}
}
JQuery
$('#customerTable').find('tr').click(function() {
var $id = $(this).closest("tr")
.find(".custId")
.text();
var $name = $(this).closest("tr")
.find(".custName")
.text();
alert($name);
$('.defaultTextBox.text_custId:text').val($id);
$('.defaultTextBox.text_custName:text').val($name);
});
In the end my goal is to get the elements clicked and set the text in my text boxes to those values, which you can see I did in the JQuery, but it only works on my first page. I need the click in my table to work on all tabs. Thanks in advance!
Edit
<div id="removeCustomer" class="tabcontent">
<h3>Pick a customer to remove!</h3>
<div class="container">
<br />
<h2 align="center">Search here to find the customer you want to remove</h2><br />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">Search</span>
<input type="text" name="search_text" id="search_text" placeholder="Search by name, phone number, email, or state" class="form-control" />
</div>
</div>
<br />
<div class="result"></div>
</div>
</div>
The "removeCustomer" id is one of the tabs. So I have multiple tabs using the same, "result", which I think is the problem I just do not know how to solve it. If I Left out "result" it would not generate a table.
Here is the JQuery which uses a php file to connect to my database and get my data. And this is what generates result.
JQuery
$(document).ready(function(){
load_data();
function load_data(query)
{
$.ajax({
url:"fetchCustomers.php",
method:"POST",
data:{query:query},
success:function(data)
{
$('div.result').html(data);
}
});
}
$('input.form-control').keyup(function(){
var search = $(this).val();
if(search != '')
{
load_data(search);
}
else
{
load_data();
}
});
});
Thanks again.
This is the code I have written in View :
<div class="col-lg-12" style="margin-bottom: 20px;">
<div class="form-group">
<label class="col-sm-3 control-label" style=" margin-top: 14px; ">Domains <font size="3" color="red">*</font></label>
<br />
<div class="col-sm-4" style="width:50%;">
#Html.ListBoxFor(m => m.SelectedDomains, Model.AllDomains,
new { #class = "chosen", multiple = "multiple", id = "drpDomains", style = "width: 350px;",onchange="FillDomain();" })
</div>
</div>
</div>
<div class="col-lg-12" style="margin-bottom: 20px;">
<div class="form-group">
<label class="col-sm-3 control-label" style=" margin-top: 14px; ">Domains new categories <font size="3" color="red">*</font></label>
<br />
<div class="col-sm-4" style="width:50%;">
#Html.ListBoxFor(m => m.SelectedDomainCategories, Enumerable.Empty<SelectListItem>(),
new { #class = "select2", multiple = "multiple", id = "multidomaincategory", style = "width: 350px;" })
</div>
</div>
</div>
<link href="~/Scripts/MultiSelect/chosen.css" rel="stylesheet" />
For Domains, I have used Chosen plugin, and for categories, i have used select2 plugin
<script type="text/javascript">
$(".chosen-deselect").chosen({ allow_single_deselect: true });
$(".chosen").chosen().change();
$(".chosen").trigger('liszt:updated');
</script>
<script>
function FillDomain() {
$("#drpDomains option[value='']").removeAttr("selected");
var selectArr = [];
$('#drpDomains').each(function () {
selectArr.push($(this).val());
});
var a = JSON.stringify(selectArr);
var reference = this;
$.ajax({
url: #Url.Content("~/MyTemplate2/FillIndustry1"), //FillIndustry1 is a method in Controller
type: "POST",
dataType: "JSON",
data: { Domain: a },
success: function (DomainCategories) {
$("#multidomaincategory").html("");
$("#multidomaincategory").removeAttr("selected");
var s = JSON.stringify(DomainCategories);
var t = JSON.parse(s);
for (var key in t) {
$("#multidomaincategory").append("<option value=" + t[key]["Value"] + ">" + t[key]["Text"] + "</option>");
}
},
error: function (data) {
alert("failure error" + data);
var t = window.JSON.parse(data.d);
alert("failueee" + t);
}
});
//I'm trying to remove all the selected items from dependent dropdown (#multidomaincategory) when all items from Domains(#drpDomains) are cleared
if ($("#drpDomains").val() == null || $("#drpDomains").val() == "") {
$("#multidomaincategory").removeAttr("selected");
$("#multidomaincategory").css('display', 'none');
}
}
</script>
Controller :
[HttpPost]
public ActionResult FillIndustry1(string Domain)
{
JArray jsonMembersArr = (JArray)JsonConvert.DeserializeObject(Domain);//convert SymptomString from json string to array
ProfessionalTrans objprofessionaltrans = new ProfessionalTrans();
string listdomains = "";
foreach (var a in jsonMembersArr)
{
listdomains = string.Join(",", a);
}
var DomainCategories = objprofessionaltrans.GetDepCategories(listdomains);
return Json(DomainCategories.ToList());
}
Data Access Layer(Transaction):
public IEnumerable<SelectListItem> GetDepCategories(string domains)
{
//GetDepCategories method - To get categories based on Domains
PTS_CommonEntities objentity = new PTS_CommonEntities();
List<SelectListItem> allskills = new List<SelectListItem>();
List<GetCatListbasedDomain> catnames = objentity.usp_GetCatListBasedOnDomains(domains).ToList();
foreach (var it in catnames)
{
allskills.Add(new SelectListItem { Value = it.CategoryID.ToString(), Text = it.CategoryName });
}
return allskills.AsEnumerable();
}
When I am clearing(closing) the selected items in Domains, the respective Categories are cleared from list, but not in the text box
Image Before Clearing
Image After Clearing the Domains
As you can see, the list is being cleared, but the selected items are still being shown in the UI.
Can someone please find out why the items are being displayed even after clearing them???
Because you are trying to clear the wrong element. #multidomaincategory is the select2 list that holds all of the values, there is a dynamic span class that gets rendered to the page right after this element, look at the html that select2 produces in your browser. Try:
$('#multidomaincategory').next().find('li').html('');
They are cleared from the list because $("#multidomaincategory").html(""); clears the html of the list of categories, not the rendered text elements in the text box.
Although a better way: $('#multidomaincategory').select2('data', null)
I'm trying to test whether content is in a text field, this works with initially loaded elements, but not the elements (which share the same class name) added using beginCollectionItem.
For example a textbox is added through bci and gets filled in, when filled in and focus goes elsewhere, the textbox will be given the 'makeitred' class.
What's wrong with the javascript I'm using?
partial using BCI
<div class="editorRow">
#using (Html.BeginCollectionItem("ispDetails"))
{
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<span>
#Html.TextBoxFor(m => m.type, new { #class = "isitempty" })
</span>
</div>
</div>
}
</div>
Index segment calling partial - on page load elements the jQuery works, anything there after using the add button doesn't
#using (Html.BeginForm())
{
<div id="editorRowsEQM">
#foreach (var item in Model.ispDetails)
{
#Html.Partial("EquipView", item)
}
</div>
#Html.ActionLink("Add", "ispManager", null, new { id = "addItemEQM", #class = "button" });
}
JS from the Index
$(function () {
$('#addItemEQM').on('click', function () {
$.ajax({
url: '#Url.Action("ispManager")',
cache: false,
success: function (html) { $("#editorRowsEQM").append(html); }
});
return false;
});
$(document).on('change', '.isitempty', function checkFill (e) {
if ($(this).val().length == 0) {
$(this).removeClass('makeitred');
} else $(this).addClass('makeitred');
});
});