Updating values being pulled from database using lou jquery multiselect - javascript

I am using lou's multiselect.js to update selected values that were previously stored in the database. I am getting the selected values from the database, however it's in the wrong column, as shown below. I would like to retrieve the values from the database that weren't selected(to be on the lef) along with those that have already been selected(to be on the right).
The list of items below(on the left) were already selected items being brought back from the database, but they should be under the Selected Product Types column instead. And then under Available Product Types the list of items that have not been selected as yet should be shown.
HTML
This gets the previously selected products from the database as shown in the picture above
<select multiple id="product-multi-select" name="product-multi-select" ng-model="input_doc_type.product" required>
#foreach($inputDocData[0]->product as $data)
<option value="{{$data->id}}" selected>{{$data->name}}</option>
#endforeach
</select>
JQuery
Gets all the products
<script type="text/javascript">
jQuery(function ($) {
$("#product-multi-select").multiSelect({
selectableHeader: "<div class='custom-header'>Available Product Types</div>",
selectionHeader: "<div class='custom-header'>Selected Product Types</div>"
});
$(document).ready(function() {
var products = [];
$.get('/admin/products/all-products', function(data, response) {
$.each(data, function(index, value) {
products.push(value.name);
});
$("#product-multi-select").multiSelect('select', products);
$(".ms-container").append('<i class="glyph-icon icon-exchange"></i>');
});
});
});
</script>
I'm not sure how to go about using this. Any assistance with this problem would be greatly appreciated.

To solve the problem I had to add an extra function in the js file which supports getting recognizing selected values (shown below). It's a replica of the addOption function that came with the file, but with one slight update.
multiselect.js
'selectedAddOption' : function(options){
var that = this;
if (options.value) options = [options];
$.each(options, function(index, option){
if (option.value && that.$element.find("option[value='"+option.value+"']").length === 0){
var $option = $('<option value="'+option.value+'" selected>'+option.text+'</option>'),
index = parseInt((typeof option.index === 'undefined' ? that.$element.children().length : option.index)),
$container = option.nested == undefined ? that.$element : $("optgroup[label='"+option.nested+"']")
$option.insertAt(index, $container);
that.generateLisFromOption($option.get(0), index, option.nested);
}
})
},
After adding that piece of code to the js file. I then made a request from the database which pulled in all unused products and then dynamically them to the select (shown below). This was added over on the Available Product Types side
// retrieve all products
$.get('/admin/products/all-products', function(data, response) {
$.each(data, function(index, value) {
$('#product-multi-select').multiSelect('addOption', { value: value.id, text: value.name, index: 0 });
});
$("#product-multi-select").multiSelect('refresh');
$(".ms-container").append('<i class="glyph-icon icon-exchange"></i>');
});
Finally, I then made another request which pulled in all products that were already selected, and this utlilized the selectedAddOption which I added to the js file. And these were then also added to the select box, over on the Selected Product Types side
// retrieve all selected products
<?php foreach ($inputDocData[0]->product as $val) { ?>
$('#product-multi-select').multiSelect('selectedAddOption', { value: <?php echo $val->id; ?>, text: '<?php echo $val->name; ?>', index: 0 });
<?php } ?>
$("#product-multi-select").multiSelect('refresh');
$(".ms-container").append('<i class="glyph-icon icon-exchange"></i>');
There are no present because they are dynamically added using jquery.
select multiple id="product-multi-select" name="product-multi-select[]" ng-model="input_doc_type.product" required></select>
The code did what it was supposed to do and there were no duplication of items in the list.
I hope this may become helpful to someone else.

Related

Is it possible to speed up iteration on large JSON file in JavaScript?

I have 3 JSON files (provinces.json, cities.json, barangays.json).
There are 88 provinces listed in the JSON file. Each province has many cities and each city has many barangays.
The provinces.json has the following sample content: (provinces are around 88 records)
{
'provCode': 01,
'provName': 'Province Name'
}
The cities.json has the following sample content: (cities are around 1647 records)
{
'ctyCode': 001,
'ctyName': 'City Name',
'provCode: 01
}
The barangays.json has the following sample content: (barangays are around 8197 records)
{
'brgyCode': 0001,
'brgyName': 'Barangay Name',
'ctyCode': 001,
'provCode: 01
}
I am using 1 dropdown select for each of the JSON files on which I trigger an onchange event to populate the next dropdown select.
The relevant code as follows:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
populateProvince();
$('#province').change(function() {
populateCity();
});
$('#city').change(function() {
populateBrgy();
});
function populateProvince() {
$('#province').html('');
$.getJSON('provinces.json', function(data){
$.each(data, function(index, object) {
$('#province').append(`<option data-code="${object.provCode}" value="${object.provName.toUpperCase()}">${object.provName.toUpperCase()}</option>`);
});
});
}
function populateCity() {
$('#city').html('');
$.getJSON('cities.json', function(data){
$.each(data, function(index, object) {
if(object.provCode === $('#province option:selected').data('code')) {
$('#city').append(`<option data-code="${object.ctyCode}" value="${object.ctyName.toUpperCase()}">${object.ctyName.toUpperCase()}</option>`);
}
});
});
}
function populateBrgy() {
$('#brgy').html('');
$.getJSON('barangays.json', function(data){
$.each(data, function(index, object) {
if(object.provCode === $('#province option:selected').data('code') && object.ctyCode === $('#city option:selected').data('code')) {
$('#brgy').append(`<option data-code="${object.brgyCode}" value="${object.brgyName.toUpperCase()}">${object.brgyName.toUpperCase()}</option>`);
}
});
});
}
});
</script>
<select id='province'></select>
<select id='city'></select>
<select id='brgy'></select>
Basically, what I do is. Upon loading the page, I populate the province select dropdown with provinces.json content.
Then upon selecting a province, I will iterate to the cities.json and check if it matches the provCode the if it matches the selected province it will populate the cities select dropdown.
Same with the barangay if it matches the selected province and city then it will populate the barangays select dropdown.
Populating provinces and cities are quite tolerable. But when I start iterating to the barangays with 8000+ records but only append around 20 records based on selected province and city the webpage stops like 10 seconds or more on an older machine and 5 seconds on newer machines.
The question is, is there an efficient way of doing this? How to speed up iterating large JSON files?
You may like to load the json files only once so on every change you can avoid call over network
$(document).ready(function() {
let provs,cities,barangays;
$.getJSON('provinces.json').done((json) =>{
provs=json;
populateProvince();// wait till you get data for province
})
$.getJSON('cities.json').done(function(json){
cities =json;
})
$.getJSON('provinces.json').done(function(json){
barangays =json;
})
$('#province').change(function() {
populateCity();
});
$('#city').change(function() {
populateBrgy();
});
function populateProvince(){
//rest of the code
}
function populateCity() {
//rest of the code
}
function populateBrgy(){
//rest of the code
}
})
Also don't append option to dom inside each iteration. Rather create a variable and append to it , then append that variable only once
function populateProvince(){
$('#province').html('');
let provOptions = ''
$.each(data, function(index, object) {
provOptions += $(`<option data-code="${object.provCode}"
value="${object.provName.toUpperCase()}">
${object.provName.toUpperCase()}
</option>`)
});
$('#province').append(provOptions)
}

.show() not working jquery

I have a filter class that filters products residing inside the page.There is a function that works if someone checks the filters.
Filters are check-boxes where every check box contains different value.
What my filter function do is that it checks all the checked checkboxes from the page and then uses the data-* global variable present on the list tages to decide what element to show.
DOM structure of the items will be:
<body>
<ul class="products">
<li class="product" data-company="something" data-flavour="something"></li>
<li class="product" data-company="something" data-flavour="something"></li>
.
.
.
.
<li class="product" data-company="something" data-flavour="something"></li>
</ul>
</body>
Below one shows the the function that does the job.
this.filterGridProducts = function() {
$.ajax({
type: 'POST',
url: 'test12.php',
data: category,
success: function(data) {
$('#limitpage').html(data);
// $('.product').hide();
var filteredProducts =$('.product');
//filter by colour, size, shape etc
var filterAttributes = $('input[type="checkbox"]');
var selectedFiltersValues = [];
// for each attribute check the corresponding attribute filters selected
filterAttributes.each(function() {
if (this.checked) {
var currentFilter = $(this);
selectedFiltersValues.push("[data-" + currentFilter.attr('name') + "='" + currentFilter.val() + "']");
filteredProducts = filteredProducts.filter(selectedFiltersValues.join(','));
}
});
filteredProducts = filteredProducts.filter(function() {
return ($(this).attr('data-price') > first && $(this).attr('data-price') <= second);
});
//console.log($('.product').show());
filteredProducts.each(function(e) {
console.log($(this).html().show()); // not working
$(this).show(); // not working
})
filteredProducts.show(); // this one is not working as well.
}
});
};
filteredProducts does contain the elements that need to be filtered but I can't seem to show it.
Ajax call in the above functions loads all the elements present inside the db, The products that come from it are all hidden.
What could be the possible reason for the .show() to not work?
Update:

Populate and display an html table based on the values from two dropdown menus

I have two cascading dropdown boxes controlled with JQuery and Ajax objects. The first determines the values in the second. Then, once a selection is made in the second, the values from the two dropdowns would be used to find a record in an SQL table and display the record in an html table.
So far the dropdowns work correctly but I'm having difficulty getting the record from the database and then displaying it on screen. I've done this before by getting the database values, sending them to the view in a Json object, and using an Ajax object to to create the table with Jquery. However, in this case I don't mind if the page reloads and would like to use a simpler method.
What is a simple method of sending two values from two dropdowns to the controller, using those values to find a record in an sql table, sending the values from the record back to the view to be displayed? Also, I don't want anything to be displayed until the second dropdown box has a selection made.
Here is what I have so far:
Controller methods:
List<Car> GetCars()
{
using (var service = new Service())
{
return service.GetCars().OrderBy(x => x.CarName).Select(x => new Car
{
CarId = x.CarId,
CarName = x.CarName
}).ToList();
}
}
List<Color> GetColors(int carId)
{
using (var service = new Services())
{
return service.GetColors(carId).OrderBy(x => x.ColorName).Select(x => new Color
{
ColorId = x.ColorId,
ColorName = x.ColorName
}).ToList();
}
}
[HttpPost]
public ActionResult CurrentSaus(int townCode, int fiscalYear)
{
var colors = GetColors(carId);
return Json(new SelectList(colors, "ColorId", "ColorName"));
}
Jquery methods:
$(document).ready(function () {
$("#Car_CarId").change(function () {
var carId = $(this).val();
var carName = $(":selected", this).text();
// put the car name into a hidden field to be sent to the controller
document.getElementById("Car_CarName").value = carName;
getColors(carId);
})
});
function getColors(carId) {
if (carCode == "") {
$("#Color_ColorId").empty().append('<option value="">-- select color --</option>');
}
else {
$.ajax({
url: "#Url.Action("Colors", "HotWheels")",
data: { colorId: clrId },
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred");
},
success: function (data) {
var colors = "";
var numberOfColors = data.length;
if (numberOfColors > 1) {
colors += '<option value="">-- select color --</option>';
}
else {
var colorId = data[0].Value;
var colorName = data[0].Text;
document.getElementById("Color_ColorName").value = colorName;
}
$.each(data, function (i, color) {
colors += '<option value="' + color.Value + '">' + color.Text + '</option>';
});
$("#Color_ColorId").empty().append(colors);
}
});
}
and some of the html:
#Html.HiddenFor(x => x.Car.CarName)
#Html.HiddenFor(x => x.Color.ColorName)
<table>
<tr>
<td> Select Car:</td>
<td style="text-align:left">
#Html.DropDownListFor(
x => x.Car.CarId,
new SelectList(Model.CarList, "CarId", "CarName"),
"-- select town --")
<br />
#Html.ValidationMessageFor(x => x.Car.CarId)
</td>
</tr>
<tr>
<td> Select Color:</td>
<td colspan="4">
#Html.DropDownListFor(
x => x.Color.ColorId,
new SelectList(Model.ColorList, "ColorId", "ColorName"),
"-- select color --")
<br />
#Html.ValidationMessageFor(x => x.Color.ColorId)
</td>
</tr>
</table>
}
The easiest method is to use an old fashion FORM element and POST the values of the two drop downs to an action in your controller. That action would expect a carId and a colorId and use them to retrieve a record from the DB and then pass the result to your 'view' where you would take care of render/display the result.
Of course using this method has some caveats:
The entire page will refresh after a user selects a value from the
second drop down.
You would have to POST the form using JavaScript
when the user picks the second option, or at least enable a button so
the form can be POSTed.
You would have to keep track of the carId and
colorId in your controller and view
Another option is to use AJAX to POST (send to the server) the carId and colorId where and action in a controller will take care of using those parameters to find a record in the DB and then return a JSON object with the result. The response will be handled by a 'success' handler where you will take care parsing the JSON object and add rows to a table.
So if you feel more comfortable working on the server side of the code pick the first option, however if you prefer to use AJAX and do this in the front end use the later.

delete row(s) from ng-grid table from button

I have a table with ng-grid, and the problem is that i'm not sure how to collect the selected row(s) id or variable to pass into my delete function.
here is a quick mockup of what i'm trying to do
http://plnkr.co/edit/zy653RrqHmBiRJ7xDHlV?p=preview
the following code is from my html, a clickable delete button that takes in 2 parameters, the array of checkbox ids and the index at the corresponding table. This delete method was obtained from this tutorial : http://alexpotrykus.com/blog/2013/12/07/angularjs-with-rails-4-part-1/
<div class="btn-group">
<button class="my-btn btn-default button-row-provider-medical-services" ng-click="deleteProviderMedicalService([], $index)">Delete</button>
</button>
</div>
<div class="gridStyle ngGridTable" ng-grid="gridOptions">
</div>
The following code grabs the json data from a url, queries it and returns it. It also contains the delete function that gets called from the controller in the html page.
app.factory('ProviderMedicalService', ['$resource', function($resource) {
function ProviderMedicalService() {
this.service = $resource('/api/provider_medical_services/:providerMedicalServiceId', {providerMedicalServiceId: '#id'});
};
ProviderMedicalService.prototype.all = function() {
return this.service.query();
};
ProviderMedicalService.prototype.delete = function(providerId) {
this.service.remove({providerMedicalServiceId: providerId});
};
return new ProviderMedicalService;
}]);
The following is my controller(not everything, just the most important bits). $scope.provider_medical_services gets the json data and puts it into the ng-grid gridOptions.
After reading the ng-grid docs, i must somehow pass the checkbox ids from the selectedItems array and pass it into html doc to the delete function. Or, i'm just doing this completely wrong, as i hacked this together. Solutions and suggestions are greatly appreciated
(function() {
app.controller('ModalDemoCtrl', ['$scope', 'ProviderMedicalService', '$resource', '$modal', function($scope, ProviderMedicalService, $resource, $modal) {
var checkBoxCellTemplate = '<div class="ngSelectionCell"><input tabindex="-1" class="ngSelectionCheckbox" type="checkbox" ng-checked="row.selected" /></div>';
$scope.provider_medical_services = ProviderMedicalService.all();
$scope.deleteProviderMedicalService = function(ids,idx) {
$scope.provider_medical_services.splice(idx, 1);
return ProviderMedicalService.delete(ids);
};
$scope.gridOptions = {
columnDefs: [
{
cellTemplate: checkBoxCellTemplate,
showSelectionCheckbox: true
},{
field: 'name',
displayName: 'CPT Code/Description'
},{
field: 'cash_price',
displayName: 'Cash Price'
},{
field: 'average_price',
displayName: 'Average Price'
},
],
data: 'provider_medical_services',
selectedItems: []
};
i think the easiest option is pass an (array index) as data-id to your dom, which u can pick it from there.
{{$index}} is a variable you can use in ng-repeat
======= ignore what i said above, since i normaly writes my own custom stuff ======
I just had a look at ng-grid, i took their example. i've added a delete all selected function, as well as someone elses delete current row function ( these is pure angular way ) to see the code, hover over the top right corner < edit in jsbin >
http://jsbin.com/huyodove/1/
Honestsly i don't like it this way, you would be better off use something like lodash to manage your arrays and do your own custom grid. Using foreach to find the row index isn't good performance.
In their doc, it says you can change the row template, and which you should, so you can add the {{index}} to that row, and filter your data through that index rather which is a little bit better. anyway beware of deleting cells after you have filter your table.
I don't quite get much your question, but you can access to selectedItems of ng-grid as following: $scope.gridOptions.$gridScope.selectedItems (see ng-grid API for more information, but technically this array holds the list of selected items in multiple mode - or only one item in single mode)
For your case, the deleteAll() function could be someething like this:
$scope.deleteAll = function() {
$scope.myData = [];
}
The delete() function which delete selected items can be:
$scope.delete = function() {
$.each($scope.gridOptions.$gridScope.selectedItems, function(index, selectedItem) {
//remove the selected item from 'myData' - it is 2-ways binding to any modification to myData will be reflected in ng-grid table
//you could check by either name or unique id of item
});
}

twitter bootstrap typeahead not working

I am working on twitter bootstrap typeahead and i am stuck as i am not getting any error and yet the auto complete is not working.
this is my input field
<input type="text" id="autocomplete" />
and this is my script
<script>
$('#autocomplete').typeahead({
source: function(process) {
var data = <?php Widgets::allProducts() ?>;
process(data);
},
matcher: function(item) {
return
item.name.toLocaleLowerCase()
.indexOf(this.query.toLocaleLowerCase()) != -1;
},
highlighter: function(item) {
return item.name;
},
updater: function (item) {
alert(JSON.parse(item).value);
return JSON.parse(item).name;
}
});
</script>
this is how my var data looks like
var data = [{"name":"Acne.org","id":"5"},{"name":"AcneFree","id":"6"},{"name":"Alpha Hydrox","id":"16"},{"name":"AmLactin","id":"17"},{"name":"Astara","id":"21"}];
What i want to do is get the product name listed (which is name in var data ) and upon selecting the product redirect the user to product page (with the help of product id which i am getting in var data as id).
I am just lost at this stage as i am not getting any error. I will appreciate any push to right direction.

Categories

Resources