how to save checked checkboxes after reloading data using ajax call - javascript

I defined a dropbox selector which after selecting a country gives me a list of cities as checkboxs. I am using jquery and ajax to preview it and select it as follow.
<div>
<div id="preview-items">
</div>
</div>
<script>
$("#id_country").change(function () {
var countryId = $(this).val(); // get the selected country ID from the HTML input
$.ajax({ // initialize an AJAX request
url: '/ajax/ajax_load_cities',
data: {
'countries': countryId // add the country id to the GET parameters
},
dataType: 'json',
success: function (data) { // `data` is the return of the `load_cities` view function
$('#preview-items').html('');
for (var i in data.tags) {
$('#preview-items').append(`
<label class="btn btn-primary mr-1">
<input type="checkbox" id="checklist_` + data.tags[i][0]+ `" value="` + data.tags[i][0] + `">
<span>
` + data.tags[i][1] + `
</span>
</label><br />`
).find("#checklist_" + data.tags[i][0]).on("change", function(e){
var cities_array = $(":checkbox:checked").map( function() { return $(this).next().html(); }).get();
$("#preview-items").html(cities_array.join(', '));
if (e.target.checked) {
localStorage.checked = true;
} else {
localStorage.checked = false;
}
}
}
});
});
</script>
and in django view.py:
def load_cities(request):
....
data = {
'tags': list(cities)
}
return JsonResponse(data)
The problem is that, it does not keep the selected cities after changing the country selectors. after googling, I found that cookies are a good choice. I wanted to know how to save selected checkboxes when dropbox items change?

I don't think you really need cookies or localstorage. I suggest you take another approach:
first you create the javascript code that builds the dropbox selector based on a state, in your example the list of cities.
then when you make the ajax call you just call that function again.
window.onload = function() {
var $container = $('#preview-items')
// when starting or loading the page I suggest either outputting the initial list
// of unchecked data in your markup somewhere as a json object
// or perform an initial ajax call. Here I just store it in a local variable.
var initialData = [
{id: 1, name: "Amsterdam", checked: false},
{id: 2, name: "Berlin", checked: true},
{id: 3, name: "Brussels", checked: false},
]
buildDropbox(initialData)
function buildDropbox(cities) {
$container.empty()
cities.forEach(function(city) {
let checked = city.checked? "checked=\"checked\"" : ""
$container.append(`
<label class="btn btn-primary mr-1" for="checklist_${city.id}">
<input type="checkbox" ${checked} id="checklist_${city.id}" value="${city.id}">
<span>${city.name}</span>
</label><br />`
)
var chk = document.getElementById("checklist_" + city.id)
chk.addEventListener("change", function(e) {
saveChange(e.currentTarget.name, e.currentTarget.value, e.currentTarget.checked)
})
})
}
function saveChange(chkName, chkValue, chkChecked) {
console.log("POST ajax for " + chkValue + " with checked: " + chkChecked);
// do your ajax call here, and in the success
// be sure to return the same list as the
// initialData, but with the updated 'checked'
// value, obviously.
// here, for testing purposes, I reuse the initialData
// and check all checkboxes randomly
let updatedData = initialData.map(function(c) {
return {...c, checked: Math.round(Math.random()) == 0}
})
buildDropbox(updatedData)
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="preview-items"></div>
</body>
</html>

Here's an example. It may not work here due to restrictions, but you can set it up to work for you.
It saves every 5 seconds and checks if its true, and if it is, save it.
var check = document.getElementById("checkbox1");
function change() {
window.setTimeout(function() {
change();
if (check.checked == true) {
localStorage.setItem("isChecked", check.checked);
}
}, 5000);
}
change();
window.onload = function() {
check.checked = localStorage.getItem("isChecked")
}
h1 {
font-family: "Comic Sans MS", sans-serif;
}
<h1>Click the check box</h1>
<br><br>
<input type="checkbox" id="checkbox1"> <!--Your Checkbox-->
I hope it works for your app!

Related

Tagify removes the tag but still remains in the textarea

I have aproblem with tagify. When I remove a tag (using tag cross), visually the tag is removed from the text area but then it is passed as a parameter via ajax. For example, if I have the following text:
Vito hello
and Vito is a tag, if I delete it, visually only hello remains but still if I send the text taking the text area via jquery still it considers me the text Vito hello.
What is the problem?
EDIT:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BigMouth v1.0</title>
<script src="../jquery.min.js"></script>
<link rel="stylesheet" href="../jquery-ui.min.css">
<script src="../jquery-ui.min.js"></script>
<script src="../tagify"></script>
<script src="../tagify.polyfills.min.js"></script>
<link href="../tagify.css" rel="stylesheet" type="text/css" />
<script src="../bootstrap.js"></script>
<link rel="stylesheet" href="../bootstrap.css">
<script>
function ShareData(){
let datepicker = document.getElementById("datepicker").value;
let oggetto = document.getElementById("oggetto").value;
let descrizione = document.getElementById("descrizione").value;
// list_added_people is a global variable
const ids = list_added_people.map(o => o.id)
// remove duplicates
const filtered = list_added_people.filter(({ id }, index) => !ids.includes(id, index + 1))
let json_form = { 'date': datepicker, 'oggetto': oggetto, 'descrizione': descrizione, 'people': filtered };
ipcRenderer.send('insert_event', JSON.stringify(json_form));
}
</script>
</head>
<body>
<div id="messages"></div>
<div style="display: none;" id="id_people"></div>
<div class="container">
<form id="myForm" action="#">
<div class="row">
<div class="row" id="title_area">
<h1>Inserisci evento:</h1>
</div>
<div class="row" id="date_area">
<div class="col">
<p>Data: <input type="text" id="datepicker"></p>
</div>
</div>
<div class="row" id="object_area">
<div class="col">
<p>Oggetto: <input type="text" id="oggetto" style=" width:50%"></p>
</div>
</div>
<div class="row" id="description_area">
<div class="col">
<p>Descrizione:</p>
<textarea id = "descrizione" name='mix'></textarea>
</div>
</div>
<div class="row" id="buttons_area">
<div class="col-xs-3">
<button type="button" class="btn btn-dark btn-block">Salva</button>
</div>
<div class="col-xs-3">
<button type="button" id = "prova" class="btn btn-danger btn-block">Cancella</button>
</div>
</div>
<button onclick="ShareData()">ShareData</button>
</div>
</form>
</div>
</div>
<style>
#date_area{
margin-top: 30px;
margin-bottom: 10px;
}
#object_area{
margin-top: 30px;
margin-bottom: 10px;
}
#description_area{
margin-top: 50px;
margin-bottom: 10px;
}
#buttons_area{
margin-top: 30px;
margin-bottom: 10px;
}
.delete_btn_area{
margin-left: 30px;
}
</style>
<script>
Array.prototype.containsArray = function (val) {
var hash = {};
for (var i = 0; i < this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
$(document).ready(function(){
var whitelist_1;
list_added_people = []
// AGGIUNGE LE PERSONE SALVATE IN DB NEL TAGGIFY
ipcRenderer.send('get_people', "ciao backend");
window.api.receivePeople((data) => {
let people = JSON.parse(data)
for(i in people){
whitelist_1.push({ value: people[i]['id'], text: people[i]['name'] + " " + people[i]['surname'], title: people[i]['name'] + " " + people[i]['surname'] })
}
})
$( function() {
$( "#datepicker" ).datepicker();
});
// Define two types of whitelists, each used for the dropdown suggestions menu,
// depending on the prefix pattern typed (#/#). See settings below.
var whitelist_1 = [
{ value: 100, text: 'kenny', title: 'Kenny McCormick' },
{ value: 1000, text: 'Mr. Mackey', title: "M'Kay" }
]
// Second whitelist, which is shown only when starting to type "#".
// Thiw whitelist is the most simple one possible.
whitelist_2 = ['Homer simpson', 'Marge simpson', 'Bart', 'Lisa', 'Maggie', 'Mr. Burns', 'Ned', 'Milhouse', 'Moe'];
// initialize Tagify
var input = document.querySelector('[name=mix]'),
// init Tagify script on the above inputs
tagify = new Tagify(input, {
// mixTagsInterpolator: ["{{", "}}"],
mode: 'mix', // <-- Enable mixed-content
pattern: /#|#/, // <-- Text starting with # or # (if single, String can be used here)
tagTextProp: 'text', // <-- the default property (from whitelist item) for the text to be rendered in a tag element.
// Array for initial interpolation, which allows only these tags to be used
whitelist: whitelist_1.concat(whitelist_2).map(function(item){
return typeof item == 'string' ? {value:item} : item
}),
dropdown : {
enabled: 1,
position: 'text', // <-- render the suggestions list next to the typed text ("caret")
mapValueTo: 'text', // <-- similar to above "tagTextProp" setting, but for the dropdown items
highlightFirst: true // automatically highlights first sugegstion item in the dropdown
},
duplicates: true,
callbacks: {
add: console.log, // callback when adding a tag
remove: console.log // callback when removing a tag
}
})
// A good place to pull server suggestion list accoring to the prefix/value
tagify.on('input', function(e){
var prefix = e.detail.prefix;
// first, clean the whitlist array, because the below code, while not, might be async,
// therefore it should be up to you to decide WHEN to render the suggestions dropdown
// tagify.settings.whitelist.length = 0;
if( prefix ){
if( prefix == '#' )
tagify.whitelist = whitelist_1;
if( prefix == '#' )
tagify.whitelist = whitelist_2;
if( e.detail.value.length > 1 )
tagify.dropdown.show(e.detail.value);
}
console.log( tagify.value )
console.log('mix-mode "input" event value: ', e.detail)
})
tagify.on('add', function(e){
let name = e.detail.data.text
let id = e.detail.data.value
console.log(list_added_people)
var flag = 0
list_added_people.push({ id: id, title: name })
})
tagify.on('remove', function(e){
let id_deleted_person = e.detail.data.value
console.log("---")
console.log(e)
console.log(list_added_people)
var keyToFind = id_deleted_person;
var person_to_delete = -1;
for (var i in list_added_people) {
if (list_added_people[i].id == keyToFind) {
person_to_delete = i
break; // If you want to break out of the loop once you've found a match
}
}
if (person_to_delete != -1) {
list_added_people.splice(person_to_delete, 1)
console.log(list_added_people)
}
//list_added_people = list_added_people.filter(e => e !== id_deleted_person)
})
})
</script>
</body>
</html>

Hide button everywhere besides specific URL in knockout

I have the following button:
<button class="btn actionButtonIcon" id="DashboardEdit" data-bind="click: changeButtonText">
<figure>
<img src="../../../Images/NotesPink.png" />
<figcaption data-bind="text: $data.ProcurementbuttonText() ? 'Save': 'Edit'"></figcaption>
</figure>
</button>
I want to only show it in this specific url
http://localhost:5595/#scorecard/ec5aa8ed-2798-4e71-b13d-f3e525994538/dashboard/PrefDashBoard
Bearing in mind that ec5aa8ed-2798-4e71-b13d-f3e525994538 is an id, thats always changing but i want it to show with all ids as well for example the button should show here as well
http://localhost:5595/#scorecard/2356789-234-234d-g3g3-reg456452/dashboard/PrefDashBoard
and i want to hide it where this isnt the url.
I tried the following code but it doesnt seem to work:
<script>
$(document).ready(function(){
if(window.location.pathname.match(/\/dashboard/PrefDashBoard))
{
$(".DashboardEdit").show();
}
else
{
$(".DashboardEdit").hide();
}
});
</script>
Here is the JS of that button:
self.ProcurementbuttonText = ko.observable(false);
self.changeButtonText = function(){
self.ProcurementbuttonText(!self.ProcurementbuttonText())
if (!self.ProcurementbuttonText()){
var data = {
'ScorecardId':ko.observable(localStorage.getItem('scorecardId'))(),
'DashboardConfig':ko.observable(localStorage.getItem('ElementDataWidget'))()
};
PreferentialProcurementDashboardApi.Save(data);
}
}
self.DashboardEdit = ko.computed({
read: function () {
var text = 'Customise your dashboard';
if (!self.EnableScorecardFeatures()) {
text = 'This feature is currently unavailable for this scorecard type';
} else {
if (!self.HasDocumentsRole()) {
text = 'You do not have sufficient rights to access the Supporting Documents view';
}
}
return text;
}
});
i think you can take advantage of the visible binding to show/hide the button based on your criteria
function PageViewModel() {
var self = this;
self.buttonVisible = ko.observable(true);
self.changeButtonText = function() {
self.ProcurementbuttonText(!self.ProcurementbuttonText());
}
self.ProcurementbuttonText = ko.observable(false);
self.buttonText = ko.pureComputed(function() {
return self.ProcurementbuttonText() ? "Save" : "Edit";
});
self.isButtonVisible = ko.computed(function() {
//do some your logic here. just need to return a true or false value;
return self.buttonVisible();
});
self.labelText = ko.pureComputed(function() {
var messageStart = "click to ";
var state = self.buttonVisible() ? 'hide' : 'show';
var messageEnd = " button";
return messageStart + state + messageEnd;
});
}
ko.applyBindings(new PageViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<button class="btn actionButtonIcon" id="DashboardEdit" data-bind="click: changeButtonText, visible: isButtonVisible, text: buttonText">
Click me.
</button>
<br/>
<br/>
<label><span data-bind="text: labelText " ></span>
<input type="checkbox" data-bind="checked: buttonVisible" />
</label>
If you have Durandal's router plugin installed and configured, you can also use the activeInstruction() observable to get info about the current route. You can then use this in your computed to check if the current fragment matches your page route.
More info here: http://durandaljs.com/documentation/api#class/Router/property/activeInstruction

How to consume ajax returned json data in DataTables and have a form in each row

I want to consume ajax returned data in my JQuery DataTables. I have created loop to view every row and also need to add a view button for them. I pass all data to JQuery DataTables. I cannot understand how to do that.
This is my ajax request
<script>
$(document).ready(function () {
$("#searchArea").show();
var uID = $("#userName").val();
var tableProduct = $('#dataTbl').DataTable({
"bSort": false
, "oLanguage": {"sZeroRecords": "", "sEmptyTable": ""}
});
$.ajax({
type: 'GET',
url: '${pageContext.request.contextPath}/restservice/viewApplication/' + uID,
success: function (result) {
var jString = JSON.stringify(result);
var jdata = JSON.parse(jString);
for (var x = 0; x < jdata.length; x++) {
var td1 = jdata[x].snumber;
var td2 = jdata[x].date;
var td3 = jdata[x].slsNo + " in " + jdata[x].slsiUnit;
var td4 = jdata[x].productDesc;
var td5 = jdata[x].status;
var td6 = "view btn1";
var td7 = "view btn2";
var td8 = "view btn3";
tableProduct.row.add([td1, td2, td3, td4, td5, td6, td7, td8]).draw(true);
}
}
});
});
</script>
I want to add this code for every row. How can I do that ?
<form method="post" action="${pageContext.request.contextPath}/viewApplication" target="_blank">
<input type="hidden" name="snumber" value="jdata[x].snumber"/>
<input type="submit" class="btn btn-primary btn-block" value="View" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
Consuming Ajax data in DataTables
There is already a handy feature in DataTables to fetch data from ajax and consume them as you configure your table. Just use the ajax option and tell about the data source you want to consume
$('#dataList').DataTable({
ajax: {
url: 'url',
type: 'GET',
dataSrc: ''
}
}
See this documentation for complete guideline.
Note: here passing dataSrc option as empty tells dataTable to expect an array rather than objects from ajax response
Following is a example that depicts a senario where datatable is configured to consume a api response. For demonastration purpose I used a public dummy api service that returned an json array. See this dummy api response.
$(function() {
var columnArray = [{
title: "Photo ID",
data: "id",
targets: 0
},
{
title: "Photo Title",
data: "title",
targets: 1
}
];
$('#dataList').DataTable({
ajax: {
url: 'https://jsonplaceholder.typicode.com/photos',
type: 'GET',
dataSrc: ''
},
bBootstrapLayout: true,
columns: columnArray,
columnDefs: [{
render: function(data, type, row) {
return data + ' (' + row['albumId'] + ')';
},
targets: 0
}, {
render: function(data, type, row) {
var html = '<button>view</button>';
return html;
},
targets: 2
}]
});
});
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet" />
<head>
<body>
<br>
<br>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-6">
<div>
<table id="dataList" class="table" data-page-length="1" cellspacing="0" width="100%" />
</div>
</div>
</div>
</body>
Having Custom button or form in row
In your datatable you can configure each column rendering logic. Like the case you are dealing, you want separate columns of button behave as form submission.
You should tell this in columnDefs option as passing an array of definations.
In the code snippet above I also showed how you can achive that. In that example I added 3rd column (target: 2) by defining its rendering logic. In render callback you can return html that should be placed in that column. I only added <button>view</button> but as you see you can return any html like forms with input fields and buttons and whats not. render option takes a function that is provided with data, type, row parameters. Hence you can exploit these data for rendering your column html or any logic you what. Thats a lot of flexibility, isn't it ?
You will find a complementary guildline from this columnDefs documentation.

How to transform the model with a select component

I want to sent to backend an attribute of the model value. To do that, I have a directive that draws a select input, with all the selectable values
Context: We have a Grails domain class defined as
class Example {
String name
EnumObject desiredToTransform
}
There is a GET Rest service returning the JSON of an instance of this object as:
{
"id": 1,
"name": "Albert"
"desiredToTransform": {
"id": "EXAMPLE_ID",
"label":"Example value"
}
}
The create Rest service for this object, receives the following arguments: [name: String, desiredToTransform:String]. If we want to create an object of this instance, we must do the following:
curl -X POST <POST_URL> -d '{"name":"Jhon Doe", "desiredToTransform":"EXAMPLE_ID"}'
The problem:
The solution I found was to create a directive which receives the model and transform the result as desired
A plunker with the solution can be found here, and shown at next on snippet
// Code goes here
var app = angular.module("app", []);
function rselectForEnum($http, $compile) {
return {
link: function(scope, elem, attrs) {
var parent = angular.element(elem.parent());
var enumerativo = attrs.enum || attrs['data-enum'] || "";
var idElem = attrs["id"] || new Date().getTime().toString();
var nameElem = attrs["name"] || idElem;
var modeloElem = attrs.ngModel;
if (typeof modeloElem === "undefined") {
throw Error("De especificar el modelo");
}
//The original data receive a parameter for a REST service in order to gather the data
// $http.get(config.apiUrl + "enumerativo/getEnum?c=" + enumerativo).then(function (response) {
// scope[nameElem + "EnumList"] = response.data.lista;
// }, function (response) {
// });
//I am going to replace it with this code
scope[nameElem + "EnumList"] = [{
id: "EXAMPLE_1",
label: "Exampple 1"
}, {
id: "EXAMPLE_2",
label: "Exampple 2"
}, {
id: "EXAMPLE_3",
label: "Exampple 3"
}, {
id: "EXAMPLE_4",
label: "Exampple 4"
}, {
id: "EXAMPLE_5",
label: "Exampple 5"
}, ]
var htmlSelect = "<select id='" + idElem + "' " +
"name='" + nameElem + "' " +
" class='form-control'>" +
"</select>";
var elemento = angular.element(htmlSelect);
elemento.attr("data-ng-model", attrs.ngModel);
elemento.attr("ng-options", "item.id as item.label for item in " + nameElem + "EnumList track by item.id");
parent.append(elemento);
elem.remove();
$compile(parent)(scope);
}
}
}
app.directive('rselectforenum', ['$http', '$compile', rselectForEnum]);
app.controller("PruebaController", PruebaController);
/*#ngInject*/
function PruebaController($scope) {
var vm = this;
$scope.modelo = {
enumerativo: {
"id": "EXAMPLE_2",
"label": "Example 2"
}
};
vm.wizzard = {
};
init();
return vm.wizzard;
function init() {
// initialize tuffs here
}
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js
"></script>
<script src="script.js"></script>
</head>
<body>
<h1>How to transform the model with a select component?</h1>
<div ng-controller="PruebaController">
<div class="row">
<div class="col-md-3">
<label class="">Probando</label>
<div class="form-line">
<rselectForEnum
id="rselectForEnumId"
data-ng-model="modelo.enumerativo"
enum="EstadoCivil"
></rselectForEnum>
</div>
</div>
</div>
<div class="row">
This is the value:
{{modelo.enumerativo}}
</div>
<br/>
<div class="row">
This is the list:<br/>
{{rselectForEnumIdEnumList}}
</div>
</div>
</body>
</html>
The result turned on the following behaviors:
When the content is loaded, the select input is selected with the model value (DESIRED)
The model keep it original value (NOT DESIRED)
On change value, model got the id attribute (DESIRED)
At first modification on the select, the label turns blank, but value is right (NOT DESIRED)
If you do not change the select and sent the form to backend, the original value is sent (NOT DESIRED)
How can I fix this?

Images in JSON AngularJS

I'm new to AngularJS, so sometimes when I do some mistake that is obvious, I still can't figure out what is going wrong with my code. So saying, here is my doubt:
HTML code:
<body ng-controller = "Ctrl">
<script id="Page6.html" type="text/ng-template">
<div class="list card" style="background-color: beige">
<div class="item item-icon-left">
<i class="icon ion-home"></i>
<input type="text" placeholder = "Enter display name" ng-model="user.nam">
</div>
<a ng-click = "saveedit(user)"<button class="button button-clear">SAVE DETAILS</button></a>
</div>
</script>
</body>
CONTROLLER.JS
.controller('Ctrl',function($scope,$rootScope,ContactService){
$rootScope.saveedit=function(user) {
ContactService.save({names: user.nam, image:"images.jpg"},ContactService.getid("Donkey"));
}
});
THIS IS THE SERVICE:
.service('ContactService', function () {
var items = [
{ id: 1, names: 'Dolphin', image: 'dolphin.jpg',}, { id: 2, names: 'Donkey', image: 'donkey.jpg'}, { id: 3, empid: 'FG2043', image: 'penguin.jpg'}];
var im = [{image: ''}];
var ctr=0;
var uid=3;
this.save = function (contact,id) {
ctr=0;
for (i=0;i<items.length;i++) {
if(items[i].id == id)
{
im[0].image= items[i].image;
ctr=100;
break;
}
}
uid = (uid+1);
contact.id = uid;
items.push(contact);
if (ctr==100 ) {
alert("in save putting the image");
items[contact.id].image = im[0].image; //doubt
alert("finished putting image");
}
}
//simply search items list for given id
//and returns the object if found
this.getid = function (name) {
for (i=0;i<items.length;i++) {
if (items[i].names == name) {
return (i+1);
}
}
}
//simply returns the items list
this.list = function () {
return items;
}
});
The problem I am facing is this: Everything works, except one thing. In ContactService, push() function, the line I have commented as //doubt is not getting executed.
The alert before it "in save putting the image" runs, but the alert "finished putting image" doesn't. What is the mistake there??
The problem here is that you're using the id's, which start at 1, to navigate in an array whose indexes start at 0.
To access the most recently pushed element, you should rather do :
items[contact.id - 1].image = im[0].image;
But you actually don't need to access the array : items[contact.id - 1] will return the object that you just pushed, and which is already referenced by variable contact, so you could just do :
contact.image = im[0].image;

Categories