Select2 ajax preselection with custom data value - javascript

So I have a multiselection dropdown with select2 and I fetch the info from a database. The thing is that prepopulating the dropdown with many values works with the example from the docs, but I also want to include an extra data field. This is how I try to populate the dropdown:
var productSelect = $('#product_ids');
$.ajax({
type: 'GET',
url: '/ajaxOrdersData/' + orderID
}).then(function (datas) {
datas.forEach(data => {
var option = new Option(data.name, data.id, true, true);
option.dataset.price = data.price;
productSelect.append(option).trigger('change');
});
productSelect.trigger({
type: 'select2:select',
params: {
data: datas.map(function (item) {
return {
text: item.nfame,
id: item.id,
price: item.price,
}
})
}
});
});
The above code does create an option tag with a data-price value but then, retrieving that value like below, doesn't work:
var products = $('#product_ids').select2('data');
The products variable doesn't have the price data attribute.
What other ways there are for me to fetch the price data attribute of all products in multiselect when clicking on a button on the DOM?

This is a solution I came up with:
var products =$('#product_ids option:selected');
And then to retrieve the value:
$.each(products, function(index, value) {
actualTotals += Number(value.dataset.price);
});
An alternative solution is to keep the .select2('data'); way of fetching the selections but instead use jquery to retrieve each elements attributes from the resulting object:
var products =$('#product_ids').select2('data');
$.each(products, function(index, value) {
price = value.element.attributes['data-price'].value;
});

Related

How to set selected values on multiple select2?

I have a multiple select2 input. I am populating all necessary options into it. After that I am sending selected values to it but these selected values are not marked on UI.
I tried below code blocks but not working either of them.
let array = [];
data.jobDepartments.map(x => {
array.push(x.id);
});
$("#jobDepartment").val(array).trigger("change");
let array = [];
data.jobDepartments.map(x => {
array.push(x.id);
});
$("#jobDepartment").select2("val", array);
Here is my settings for select2 input.
<select id="jobDepartment" name="jobDepartment" class="form-control select2" multiple="multiple" data-toggle="tooltip" data-trigger="hover" data-placement="top" data-title="jobDepartment"></select>
$(document).ready(function () {
$(".select2").select2();
});
let array = [];
data.jobDepartments.map(x => {
array.push(x.id);
});
$("#jobDepartment").val(array).trigger("change");
Result is: https://prnt.sc/pn0v94
I was expecting this: https://prnt.sc/pn0vvb
Could you help me with it?
Try this Fiddle
Following things are missing in your code:
you should have data config while creating select2
$("#e9").select2({
placeholder: "Select a State",
allowClear: true,
templateSelection:function(obj){
return obj.title;
},
data: [{
'id': 1,
title: 'test'
}, {
'id': 2,
title: 'test1'
}
]
});
then you have fire your change
I solved the problem. Mistake was coming data. My data id was wrong.

Axios get call fired on select

I am receiving multiple json files from a server. They are all accessible on different urls based on years (2018,2019 and 2020). I am prefilling these years into a dropdown but now I want to fire a get call with axios everytime I change the value(?year=2018, ?year=2019 or ?year=2020). I also have another dropdown that is prefilled with IDs but have no idea how to attach a certain ID to selected year. These dropdowns are acting as filter for a table that is rendered below.
So to be more clear, when I reload I fire a get call for current year like so: baseurl?year=2019, with this selection I get ALL the data but then if I select an ID, this ID needs to be added to url like so:
baseurl?year=2019?id=0
My current code:
data() {
return {
year:[],
id: 0,
}
},
computed: {
axiosParams(){
const params = new URLSearchParams();
params.append('year', this.year);
return params;
},
//this returns my current year
year() {
var now = new Date()
var nowy = now.getFullYear()
return nowy
},
//this method makes sure that the dropdown is always preffiled
//with following years - eg. next year I only need 2019, 2020 and
//2021
years() {
var yearsArray = []
var now = new Date()
for (let i = -1; i < 2; i++) {
var nowy = now.getFullYear() + i
yearsArray.push(nowy)
}
return yearsArray
},
},
methods: {
getYears: function() {
axios.get('myurl',{
params : this.axiosParams
}
}).then((response) => {
this.year = response.data;
this.table = response.data;
})
},
getId: function() {
axios.get('myurl',{
params : {
year: this.year,
id : this.id
}
}
}).then((response) => {
this.id = response.data;
this.table = response.data;
})
},
},
created: {
this.getYears();
this.getId();
}
My HTML:
<select v-model="year">
<option v-model="yearsArray" v-for="year in years">{{year}} .
</option></select>
<select v-model="id"><option v-for="item in id">{{item}}</option> .
</select>
Thanks!
So, if I understand, you want to trigger an axios call when an id is selected. This can be done a couple of ways but this way will trigger on the selection of an id, and also on the selection of a year.
<select v-model="selectedYear" #change="yearSelected">
<option v-for="year in years" :key="year" :value="year">{{year}} .</option>
</select>
<select v-model="selectedId" #change="idSelected">
<option v-for="id in ids" :key="id" :value="id">{{id}}</option> .
</select>
Here, the years is from your computed property for years and ids is what you said was a dropdown "prefilled with IDs". The two v-model properties are initially set to null then are assigned a value on selection. They are defined in data like so.
data: () => ({
selectedId: null,
selectedYear: null,
}),
Each has a function call to do something with the selected option, #change="idSelected" which calls this method:
methods: {
idSelected() {
console.log(this.selectedId)
// here you make you axios call using this.selectedId as the param
axios.get('myurl',{
params : {
year: this.selectedYear,
id : this.selectedId
}
},
...
}
You could have the two selects without the #change and have a button that triggers the function call with #click. Either way you use the selectedId and selectedYear in that method.

How to use select2 with multiple options using Razor and MVC

I am trying to create a multiple choice list using Select2, Razor and the MVC framework. My problem is that the object in the controller that receives the array input is always null. The front-end looks as follows:
<form class="form-horizontal" method="post" action="#Url.Action(MVC.Configurazione.Contatori.Edit())">
<div class="form-group">
<div class="col-lg-8">
<select class="form-control attributoSelect2" name="attributiSelezionati" value="#Model.AttributiSelezionati">
<option value="#Model.AttributiSelezionati" selected>#Model.AttributoDescrizione</option>
</select>
</div>
</div>
</form>
The action method "Edit", is the controller method that receives the array of chosen items from the drop-down list.
The Javascript is the following:
$('.attributoSelect2').select2({
placeholder: "Search attribute",
multiple: true,
allowClear: true,
minimumInputLength: 0,
ajax: {
dataType: 'json',
delay: 150,
url: "#Url.Action(MVC.Configurazione.Attributi.SearchAttrubutes())",
data: function (params) {
return {
search: params.term
};
},
processResults: function (data) {
return {
results: data.map(function (item) {
return {
id: item.Id,
text: item.Description
};
})
};
}
}
});
And finally the C# controller has an object that is expected to retrieve the data from the view and is defined:
public string[] AttributiSelezionati { get; set; }
and the HttpPost method that receives the data is:
[HttpPost]
public virtual ActionResult Edit(EditViewModel model) { }
Could someone give me some insight into what I am doing wrong and the areas that I should change in order to find the problem?
you class name error not attributoSelect2 is attributesSelect2 , I also make this mistake often. haha
<select class="form-control attributoSelect2" name="attributiSelezionati" value="#Model.AttributiSelezionati">
<option value="#Model.AttributiSelezionati" selected>#Model.AttributoDescrizione</option>
</select>
There are multiple reason for not being receiving data on server. First of all you need to change your select code as follow
#Html.DropDownList("attributiSelezionati", Model.AttributiSelezionati, new { #class = "form-control attributo select2" })
now go to console in browser and get the data of element to confirm that your code properly works in HTML & JS
After that you need to add attribute at your controller's action method as
[OverrideAuthorization]
[HttpPost]
You can try the following approach that has been used in some of our projects without any problem:
View:
#Html.DropDownListFor(m => m.StudentId, Enumerable.Empty<SelectListItem>(), "Select")
$(document).ready(function () {
var student = $("#StudentId");
//for Select2 Options: https://select2.github.io/options.html
student.select2({
language: "tr",//don't forget to add language script (select2/js/i18n/tr.js)
minimumInputLength: 0, //for listing all records > set 0
maximumInputLength: 20, //only allow terms up to 20 characters long
multiple: false,
placeholder: "Select",
allowClear: true,
tags: false, //prevent free text entry
width: "100%",
ajax: {
url: '/Grade/StudentLookup',
dataType: 'json',
delay: 250,
data: function (params) {
return {
query: params.term, //search term
page: params.page
};
},
processResults: function (data, page) {
var newData = [];
$.each(data, function (index, item) {
newData.push({
//id part present in data
id: item.Id,
//string to be displayed
text: item.Name + " " + item.Surname
});
});
return { results: newData };
},
cache: true
},
escapeMarkup: function (markup) { return markup; }
});
//You can simply listen to the select2:select event to get the selected item
student.on('select2:select', onSelect)
function onSelect(evt) {
console.log($(this).val());
}
//Event example for close event
student.on('select2:close', onClose)
function onClose(evt) {
console.log('Closed…');
}
});
Controller:
public ActionResult StudentLookup(string query)
{
var students = repository.Students.Select(m => new StudentViewModel
{
Id = m.Id,
Name = m.Name,
Surname = m.Surname
})
//if "query" is null, get all records
.Where(m => string.IsNullOrEmpty(query) || m.Name.StartsWith(query))
.OrderBy(m => m.Name);
return Json(students, JsonRequestBehavior.AllowGet);
}
Hope this helps...
Update:
Dropdown option groups:
<select>
<optgroup label="Group Name">
<option>Nested option</option>
</optgroup>
</select>
For more information have a look at https://select2.org/options.

unique nested ng-repeat populated from database

i am trying to get unique values for a nested ng-repeat
there are the two scopes i am working with
$scope.AllGames = [
{ title: "Doom", productCode: "458544", id_product: "1" },
{ title: "Wolvenstein", productCode: "457104", id_product: "2" },
{ title: "Quake", productCode: "32542687", id_product: "3" }
];
$scope.AllPrices= [
{ id_productPrice: "1", id_product: "1", price : "599" },
{ id_productPrice: "2", id_product: "1", price : "699" },
{ id_productPrice: "3", id_product: "2", price : "249" }
];
this is the html
<div ng-repeat="game in AllGames">
<div>{{game.title}} | {{game.id_product}} | {{game.title}}</div>
<div ng-init="getPriceByGame(game.id_product)">
<div ng-repeat="item in AllPrices">
{{item.price}}
</div>
</div>
and this is the controller
$scope.getAllGames = function () {
var request = 'Games';
$http({
method: 'Get',
url: uri + request
})
.success(function (data) {
$scope.AllGames = data;
})
}
$scope.getPriceByGame = function (id_product) {
var request = AllPrices/' + id_product;
$http({
method: 'Get',
url: uri + request
})
.success(function (data) {
$scope.AllPrices = data;
})
};
So the idea is that i send the id_product to the database and i get a list of prices back for that id, i would like to connect these prices for each unique product. what happens now is that the ng-init works fine and the request gets send with the id, i receive the prices for that id. In the console log i see all the prices coming in by product_id (all different arrays) but i can't seem to connect them in the html so i actually see the prices.
The last request overwrites of course all the prices for each game in the ng-repeat. How do i keep this unique? So that each product gets the prices for that id.
You could place another ng repeat to loop through the all Prices array. Every time you get new data, you push it to the array.
Don't forget to make an edit in the nested ng repeat of all prices, it should loop only through the current index

How to implement search with two terms for a collection?

So, currently I have a collection of items where I want the user to be able to search using the name and some random text from the collection.
Here's what I have done so far:
public IEnumerable<Item> items = new[]
{
new Item { ItemId = 1, ItemName = "Apple", ItemDescription = "crispy, sweet", ItemPairing = "Walnut"},
new Item { ItemId = 2, ItemName = "Pear", ItemDescription = "slightly tart", ItemPairing = "Cheese"},
new Item { ItemId = 3, ItemName = "Banana", ItemDescription = "good source of potassium", ItemPairing = "Honey" },
new Item { ItemId = 4, ItemName = "Chocolate", ItemDescription = "Sweet and rich melting flavor", ItemPairing = "Wine"}
};
public ActionResult Index()
{
return View("Index");
}
public ActionResult Search(string search)
{
return View("Index", items.Where(n => n.ItemName.StartsWith(search)));
}
Here's the search part on the view:
<p>
<b>Search for Name:</b>
#Html.TextBox("ItemName", "", new { #class = "form-control" })
<b>Search for Text:</b>
#Html.TextBox("ItemText", "", new { #class = "form-control" })
<input id="search" type="submit" value="Search" onclick="search(ItemName,ItemText)" />
</p>
<script>
function search(ItemName, ItemText) {
$("search").click(function () {
$.ajax({
type: "POST",
url: "/Items/Search",
data: {ItemName, ItemText},
datatype: "html",
success: function (data) {
$('#result').html(data);
}
});
});
}
</script>
So that it can look something like this:
I want it so that when the user types in Apple for Name and Crispy for text, they can find the Apple item from my collection. I also want it so that if they type in either Name or Text, it will still return a matched item.
I'm not sure how to do that.
Remove the onclick attribute from the submit button and change it to
<button type="button" id="search">Search</button>
and change the script to
var url = '#Url.Action("Search", "Items")';
$("#search").click(function () {
$.post(url, { ItemName: $('#ItemName').val(), ItemText: $('#ItemText').val() }, function(data) {
$('#result').html(data);
});
})
Note you may want to consider making it $.get() rather than $.post()
and change the controller method to accept the inputs from both textboxes
public PartialViewResult Search(string itemName, string itemText)
{
var items = ??
// filter the data (adjust to suit your needs)
if (itemName != null)
{
items = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
}
if (itemText != null)
{
items = items.Where(x => x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
}
// query you data
return PartialView("_Search", items);
}
Side note: Its not clear what the logic for search is - i.e. if you enter search text in both textboxes, do you want an and or an or search
Assuming the view in the view in the question is Index.cshtml, then it will include the following html
<div id="result">
#Html.Action("Search") // assumes you want to initially display all items
</div>
and the _Search.cshtml partial would be something like
#model IEnumerable<Item>
#foreach (var item in Model)
{
// html to display the item properties
}
While CStrouble's answer will work, if you're into AJAX calls and want to sort this in a single page, you might consider using AJAX and JQuery calls.
With AJAX & JQuery:
var search = function(itemName, itemText) {
//note that if you want RESTful link, you'll have to edit the Routing config file.
$ajax.get('/controller/action/itemName/itemText/', function(res) {
//do stuff with results... for instance:
res.forEach(function(element) {
$('#someElement').append(element);
});
});
};
And the action:
public JsonResult SearchAction(itemName, itemText) {
List<Item> newItems = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
|| x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
|| x.ItemPairing.ToUpperInveriant().Contains(itemText.ToUpperInveriant()));
return Json.Encode(newItems.ToArray());
}
Note that I'm not home, so there might be some syntax errors.
Alright, so say I want to return a partial, instead of a simple array:
first, change the action to:
public ActionResult SearchAction(itemName, itemText) {
List<Item> newItems = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
|| x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
|| x.ItemPairing.ToUpperInveriant().Contains(itemText.ToUpperInveriant()));
return PartialView("~/Views/Partials/MyPartialView.cshtml", newItems);
}
And you create a partial view in the directory you specified, taking the model that you transferred (newItems)
#model IEnumerable<Path.to.Item>
<h3>Results</h3>
<ul>
#foreach(var item in model)
{
<li>#item.Name - #item.Description</li>
}
</ul>
and now when you receive the jquery response:
$.ajax({
type: "POST",
url: "/Items/Search",
data: {ItemName, ItemText},
datatype: "html",
success: function (data) {
$('#result').html(data);
}
});
//since data is the HTML partial itself.
//if you have firebug for Mozilla firefox, you can see what I'm
//talking about
You may want to consider converting both strings to upper or lower, depending on your search requirements. The below code assumes the search is case-insensitive.
public ActionResult Search(string search)
{
string upperSearch = search.ToUpperInvariant();
return View("Index", items.Where(n =>
n.ItemName.ToUpperInvariant().StartsWith(search) ||
n.ItemDescription.ToUpperInvariant().Contains(search)));
}
with the Or condition it will match if either the text or the name matches. If they match different items (like Apple and Tart), you may need to consider what happens in that use-case, but in this case it will return both Apple and Pear.

Categories

Resources