Modifying JS pager - how to substitute html elements using JQuery - javascript

Here is the initial code:
<div class="fs-table-table">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div id="fs-table-content">
</div>
</div>
Now the pager file calls:
$('#' + options.contentHolder).html(template(pager, options.template, options.currentData, options.startPage, options.perPage, options.alwaysShowPager, options.informationToShow, options.errorTemplate));
where contentHolder is 'fs-table-content', and it points to a template:
<script type="text/template" id="weeklyLessonTemplate">
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
##courseName##
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="##lessons##" />
<label for="##lessons##">##lessons##
</label>
</div>
</div>
</script>
and it yields:
<div class="fs-table-table">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
Art/Music/Social Media
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="What is art?">
<label for="What is art?">What is art?
</label>
</div>
</div>
</div>
So you see, calling the function "template" simply returns html code. Now, when I click on the next page number, I expect the html to change but it doesn't change, it stays the same because
<div id="fs-table-content">
</div>
has been replaced. How do I inject fs-table-content back into the code. It should be put in the page onclick code:
$('#' + pager).on('click', '.page, .last-page, .first-page, .next-pages, .prev-pages', function(e) {
var newPage = parseInt($(this).data('value'));
var perPage = parseInt($('#' + pager + ' .perPage').val());
$('#' + pager + ' .page.current').removeClass('current');
$('#' + pager + ' .page[data-value="' + newPage + '"]').addClass('current');
showProperPaging(pager, newPage, options.totalPages, options.pagesToShow);
$('#' + options.contentHolder).html(template(pager, options.template, options.currentData, newPage, perPage, options.alwaysShowPager, options.informationToShow, options.errorTemplate));
options.currentPage = newPage;
$('#' + pager).trigger("pagingChange");
});
I noticed that in the demo for the pager, they use the following line to change the html:
var showing = $('#' + templateToShow).html().format(data);
html += showing;
But my data is structured differently, I don't think I can use .format

The way this script has been designed is that you need to provide two separate divs (not nested within one another). One for your content and one of its content (where it places pagination, search .. etc).
So you can change your code to this for it work:
!function(a){function e(e,t,r,n,o,s,g){var p="",l=Math.ceil(t/r);p+='<div class="showing"></div>',p+='<div class="pager"><span class="first-page btn" data-value="1">First</span><span class="prev-page btn">Previous</span><span class="prev-pages btn" data-value="1">...</span><span class="page btn current" data-value="1">1</span>';for(var i=1;i<l;i++)p+='<span class="page btn" data-value="'+(i+1)+'">'+(i+1)+"</span>";p+='\t<span class="next-pages btn" data-value="6">...</span><span class="next-page btn">Next</span><span class="last-page btn" data-value="'+l+'">Last</span></div>',p+='<div class="options" style="text-align: center; margin-bottom: 10px;"><span>Show </span><select class="perPage">';for(i=0;i<n.length;i++)n[i]==r?p+='<option selected="selected">'+n[i]+"</option>":p+="<option>"+n[i]+"</option>";p+="\t</select><span> per page</span></div>",s&&(p+='<div class="searchBox"><input type="text" class="search" placeholder="Search" value="'+g+'" /></div>'),a("#"+e).html(p)}function t(e,t,r,n){1==t?a("#"+e).find(".prev-page").hide():a("#"+e).find(".prev-page").show(),t==r?a("#"+e).find(".next-page").hide():a("#"+e).find(".next-page").show();var o,s,g=n,p=Math.ceil(g/2),l=Math.floor(g/2);r<g?(o=0,s=r):t>=1&&t<=p?(o=0,s=g):t+l>=r?(o=r-g,s=r):(o=t-p,s=t+l),a("#"+e+" .pager").children().each(function(){a(this).hasClass("page")&&a(this).hide()});for(var i=o;i<s;i++)o>0?(a("#"+e+" .prev-pages").show(),a("#"+e+" .prev-pages").data("value",o)):a("#"+e+" .prev-pages").hide(),a("#"+e+" .page[data-value='"+(i+1)+"']").show(),s<r?(a("#"+e+" .next-pages").show(),a("#"+e+" .next-pages").data("value",s+1)):a("#"+e+" .next-pages").hide();1==r?a("#"+e+" .last-page, #"+e+" .first-page").hide():0==r?a("#"+e+" .pager, #"+e+" .showing, #"+e+" .options").hide():(a("#"+e+" .pager, #"+e+" .showing, #"+e+" .options").show(),a("#"+e+" .last-page, #"+e+" .first-page").show())}function r(e,t,r,n,o,s,g,p){var l="",i=n*o-(o-1),h=n*o>r.length?r.length:n*o;if(r.length<=0){if(""==p)l+='<div class="dataError">There is nothing to show here.</div>';else l+=a("#"+p).html().format(["There are no Messages to display."]);return s||a("#"+e).hide(),l}a("#"+e).show(),a("#"+e+" .showing").html("Showing "+i+" to "+h+" of "+r.length+" total.");for(var c=n*o-o;c<n*o&&c!=r.length;c++){var u=[];a.each(g,function(a,e){u.push(r[c][e])}),l+=a("#"+t).html().format(u)}return l}a.fn.extend({paging:function(n){var o={data:{},contentHolder:"",template:"",errorTemplate:"",informationToShow:[],informationToRefineBy:[],perPage:10,pageLengths:[5,10,20,30,40,50],startPage:1,pagesToShow:5,showOptions:!0,showSearch:!0,alwaysShowPager:!0},s={currentPage:o.startPage,totalPages:0,currentData:n.data,refine:""};n=a.extend(o,n),(n=a.extend(s,n)).totalPages=Math.ceil(n.currentData.length/n.perPage),function(n,o){o.totalPages;e(n,o.currentData.length,o.perPage,o.pageLengths,o.showOptions,o.showSearch,o.refine),t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,o.perPage,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),a("#"+n).on("click",".page, .last-page, .first-page, .next-pages, .prev-pages",function(e){var s=parseInt(a(this).data("value")),g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("click",".next-page",function(e){var s=o.currentPage+1,g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("click",".prev-page",function(e){var s=o.currentPage-1,g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("change",".perPage",function(s){var g=parseInt(a(this).val());e(n,o.data.length,g,o.pageLengths,o.showOptions,o.showSearch,o.refine),o.totalPages=Math.ceil(o.currentData.length/g),t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=o.startPage,a("#"+n).trigger("pagingChange")}),a("#"+n).on("keyup",".search",function(e){var s=parseInt(a("#"+n+" .perPage").val()),g=a(this).val();o.refine=g;var p=function(e,t,r){if(""==t)return;var n=t.toLowerCase();dataToKeep=[];for(var o=0;o<e.length;o++)a.each(r,function(a,t){if(null!=e[o][t]&&e[o][t].toLowerCase().indexOf(n)>=0)return dataToKeep.push(e[o]),!1});return dataToKeep}(o.data,g,o.informationToRefineBy);p||(p=o.data),o.currentData=p;var l=Math.ceil(o.currentData.length/s);o.totalPages=l,t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,s,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),a("#"+n).trigger("pagingChange")}),a("#"+n).on("focusin",".search",function(){o.refineFocus=!0}),a("#"+n).on("focusout",".search",function(){o.refineFocus=!1})}(a(this).attr("id"),n)}})}(jQuery),String.prototype.format=function(){var a=arguments;return this.replace(/{(\d+)}/g,function(e,t){return void 0!==a[0][t]?a[0][t]:e})};
$(document).ready(function() {
var data = [{
"firstname": "John",
"lastname": "Smith"
}, {
"firstname": "Jane",
"lastname": "Doe"
}, {
"firstname": "James",
"lastname": "Smith"
}, {
"firstname": "Amanda",
"lastname": "Doe"
}, {
"firstname": "Billy",
"lastname": "Joe"
}];
$('#fs-table-table').paging({
data: data, //This is the data that is being used. It is using JSON data so you can pull from any source if you want.
contentHolder: 'fs-table-content', //The id for the area where you want the data to be displayed.
template: 'weeklyLessonTemplate', //The template that is being used to display the data.
errorTemplate: 'contentErrorTemplate', //The error template that is being used (optional)
informationToShow: ['firstname', 'lastname'], //The information that you want to show from the given data
informationToRefineBy: ['firstname', 'lastname'], //The information that you want to search on from the given data
perPage: 1, //Default number to show per page. (Since we have a small amount of data only show 1.)
pageLengths: [1, 2, 3, 4], //Options for number of items per page.
startPage: 1, //The default start page. (Better to leave as 1 but can be changed if desired).
pagesToShow: 4, //Number of pages to show at the top. If you have 10 pages it will show [...] when going above or below the this number.
showOptions: true, //Show the per page options.
showSearch: true, //Show the search bar.
alwaysShowPager: true //Show the pager even if there isn't any data. Should be true if showSearch is true otherwise there will be problems.
});
});
.pager span.current {
border: red;
border-radius: 5px;
font-weight: bold;
color: red;
}
.dataError {
width: 100%;
font-size: 20px;
text-align: center;
padding: 10px;
}
.searchBox {
width: 300px;
margin: 0 auto;
}
.searchBox .search {
width: 100%;
height: 30px;
}
.showing {
width: 100%;
text-align: center;
}
.dropdown:hover .dropdown-menu { display: block; }
.pager span {
border-radius: 5px;
border: #a6a6a8 1px solid;
padding: 5px 14px;
margin: 0 3px;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.pager span:hover { background-color: #ddd; }
.pager span.current:hover {
background-color: #fff;
cursor: default;
}
.pager {
padding-left: 0;
margin: 20px 0;
text-align: center;
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="fs-table-content"></div>
<div id="fs-table-table"></div>
<script type="text/template" id="weeklyLessonTemplate">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div id="fs-table-content">
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
{0}
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="{1}" />
<label for="{1}">{1}</label>
</div>
</div>
</div>
</script>

Related

How to match user input with array data in JavaScript

I'm new in learning HTML, JavaScript and CSS. I'm stuck at this JavaScript code.
I'm trying to match user input on the searchbar with some city array list I already prepared, when the search result match the script will change the display style of element into showing the result of their search value, but until now the result always showing false value.
Is there any better way to do this? Is there something wrong with my code?
function searchRespond() {
if (document.getElementById("myInput").value.match(cities))
{
document.getElementById("areaCovered").style.display = "block";
}
else {
document.getElementById("areaNotCovered").style.display = "block";
document.getElementById("searchResult").innerHTML = document.getElementById("myInput").value;
}
}
var cities = ["Banda Aceh", "Bandar Lampung", "Banyuwangi", "Bandung", "Bali", "Batam", "Batu", "Bekasi", "Bengkulu", "Binjai", "Blitar", "Bogor", "Bukittinggi", "Cimahi", "Cirebon", "Denpasar", "Depok", "Dumai", "Gunungsitoli", "Jakarta", "Jambi", "Kediri", "Langsa", "Lhokseumawe", "Lombok", "Lubuklinggau", "Madiun", "Magelang", "Malang", "Medan", "Metro", "Mojokerto", "Padang", "Padang Sidempuan", "Padangpanjang", "Pagar Alam", "Palembang", "Pangkal Pinang", "Pariaman", "Pasuruan", "Payakumbuh", "Pekalongan", "Pekanbaru", "Pematangsiantar", "Prabumulih", "Prigi", "Probolinggo", "Sabang", "Salatiga", "Sawahlunto", "Semarang", "Serang", "Sibolga", "Solo", "Subussalam", "Sukabumi", "Sumbawa", "Sungaipenuh", "Surabaya", "Surakarta", "Tangerang", "Tangerang Selatan", "Tanjungbalai", "Tanjungpinang", "Tasikmalaya", "Tebing Tinggi", "Tegal", "Yogyakarta"];
.HeadlineSearchContainer {
position: relative;
top: 100px;
margin: auto;
height: 159px;
}
.SearchCharacterStyle {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
.searchrespond {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
#areaCovered {
display: none;
}
#areaNotCovered {
display: none;
}
#fillArea {
display: none;
}
<div class="HeadlineSearchContainer">
<div class="SearchCharacterStyle">
<h>SEARCH FOR AREA COVERANGE</h>
</div>
<div id="mySearch" class="searchbox_box">
<form autocomplete="off" name="myForm">
<div class="autocomplete" style="width:300px;">
<input id="myInput" type="text" name="city" placeholder="Enter Your Destination City">
<i class="searchbutton"></i>
</div>
<input type="button" formtarget="_new" onclick="searchRespond()" name="input" value="Search">
<div class="searchrespond" id="searchRespond">
<h id="areaCovered">YES! We cover your area destination</h>
<h id="areaNotCovered">We don't cover your area destination yet
<p id="searchResult"></p>
</h>
<h id="fillArea">Please fill your area destination first</h>
</div>
</form>
</div>
</div>
To do what you require you can use filter() to match the user's input to values in your array. You would be best to perform a case-insensitive match, which can be done by converting both values to the same case.
Note that this logic sets the notifications as hidden before the logic runs, so that the previous state of the search is removed.
In addition, I made a couple of improvements to the code. Firstly I stored the relevant elements in variables instead of accessing the DOM every time. This is slightly more performant, and makes the code a lot easier to read. I also used addEventListener() to bind events instead of inline event handlers in the HTML, which are bad practice and shouldn't be used. Lastly I converted the <h> elements to <h2 /> in this demo, as there is no <h> element in HTML.
const input = document.querySelector('#myInput');
const areaCovered = document.querySelector('#areaCovered');
const areaNotCovered = document.querySelector('#areaNotCovered');
const searchResult = document.querySelector('#searchResult');
const fillArea = document.querySelector('#fillArea');
const cities = ["Banda Aceh", "Bandar Lampung", "Banyuwangi", "Bandung", "Bali", "Batam", "Batu", "Bekasi", "Bengkulu", "Binjai", "Blitar", "Bogor", "Bukittinggi", "Cimahi", "Cirebon", "Denpasar", "Depok", "Dumai", "Gunungsitoli", "Jakarta", "Jambi", "Kediri", "Langsa", "Lhokseumawe", "Lombok", "Lubuklinggau", "Madiun", "Magelang", "Malang", "Medan", "Metro", "Mojokerto", "Padang", "Padang Sidempuan", "Padangpanjang", "Pagar Alam", "Palembang", "Pangkal Pinang", "Pariaman", "Pasuruan", "Payakumbuh", "Pekalongan", "Pekanbaru", "Pematangsiantar", "Prabumulih", "Prigi", "Probolinggo", "Sabang", "Salatiga", "Sawahlunto", "Semarang", "Serang", "Sibolga", "Solo", "Subussalam", "Sukabumi", "Sumbawa", "Sungaipenuh", "Surabaya", "Surakarta", "Tangerang", "Tangerang Selatan", "Tanjungbalai", "Tanjungpinang", "Tasikmalaya", "Tebing Tinggi", "Tegal", "Yogyakarta"];
document.querySelector('#search-from').addEventListener('submit', e => {
e.preventDefault();
const searchTerm = input.value.trim().toLowerCase();
fillArea.style.display = 'none';
areaCovered.style.display = 'none';
areaNotCovered.style.display = 'none';
if (!searchTerm) {
fillArea.style.display = 'block';
return;
}
let matches = cities.filter(city => city.toLowerCase() == searchTerm);
if (matches.length) {
areaCovered.style.display = 'block';
} else {
areaNotCovered.style.display = 'block';
}
});
.HeadlineSearchContainer {
position: relative;
top: 100px;
margin: auto;
height: 159px;
}
.SearchCharacterStyle {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
.searchrespond {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
#areaCovered {
display: none;
}
#areaNotCovered {
display: none;
}
#fillArea {
display: none;
}
.autocomplete {
width: 300px;
}
<div class="HeadlineSearchContainer">
<div class="SearchCharacterStyle">
<h>SEARCH FOR AREA COVERANGE</h>
</div>
<div id="mySearch" class="searchbox_box">
<form autocomplete="off" name="myForm" id="search-from">
<div class="autocomplete">
<input id="myInput" type="text" name="city" placeholder="Enter Your Destination City">
<i class="searchbutton"></i>
</div>
<button type="submit">Search</button>
<div class="searchrespond" id="searchRespond">
<h2 id="areaCovered">YES! We cover your area destination</h2>
<h2 id="areaNotCovered">We don't cover your area destination yet</h2>
<h2 id="fillArea">Please fill your area destination first</h2>
</div>
</form>
</div>
</div>
You can use javascript includes().
<script>
const fruits = ["Banana Aceh", "Orange", "Apple", "Mango"];
let str = "Banana Aceh"; //document.getElementById("myInput").value
if(fruits.some(v => str.includes(v))) {
console.log("Exists");
} else {
console.log("Did not Exists");
}
</script>
function searchRespond() {
let searchTerm = document.getElementById("myInput").value;
if (cities.find(city => city == searchTerm))
{
document.getElementById("areaCovered").style.display = "block";
}
else {
document.getElementById("areaNotCovered").style.display = "block";
document.getElementById("searchResult").innerHTML = document.getElementById("myInput").value;
}
}
var cities = ["Banda Aceh", "Bandar Lampung", "Banyuwangi", "Bandung", "Bali", "Batam", "Batu", "Bekasi", "Bengkulu", "Binjai", "Blitar", "Bogor", "Bukittinggi", "Cimahi", "Cirebon", "Denpasar", "Depok", "Dumai", "Gunungsitoli", "Jakarta", "Jambi", "Kediri", "Langsa", "Lhokseumawe", "Lombok", "Lubuklinggau", "Madiun", "Magelang", "Malang", "Medan", "Metro", "Mojokerto", "Padang", "Padang Sidempuan", "Padangpanjang", "Pagar Alam", "Palembang", "Pangkal Pinang", "Pariaman", "Pasuruan", "Payakumbuh", "Pekalongan", "Pekanbaru", "Pematangsiantar", "Prabumulih", "Prigi", "Probolinggo", "Sabang", "Salatiga", "Sawahlunto", "Semarang", "Serang", "Sibolga", "Solo", "Subussalam", "Sukabumi", "Sumbawa", "Sungaipenuh", "Surabaya", "Surakarta", "Tangerang", "Tangerang Selatan", "Tanjungbalai", "Tanjungpinang", "Tasikmalaya", "Tebing Tinggi", "Tegal", "Yogyakarta"];
.HeadlineSearchContainer {
position: relative;
top: 100px;
margin: auto;
height: 159px;
}
.SearchCharacterStyle {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
.searchrespond {
font-family: Roboto;
font-size: 12px;
line-height: 24.82px;
text-align: left;
}
#areaCovered {
display: none;
}
#areaNotCovered {
display: none;
}
#fillArea {
display: none;
}
<div class="HeadlineSearchContainer">
<div class="SearchCharacterStyle">
<h>SEARCH FOR AREA COVERANGE</h>
</div>
<div id="mySearch" class="searchbox_box">
<form autocomplete="off" name="myForm">
<div class="autocomplete" style="width:300px;">
<input id="myInput" type="text" name="city" placeholder="Enter Your Destination City">
<i class="searchbutton"></i>
</div>
<input type="button" formtarget="_new" onclick="searchRespond()" name="input" value="Search">
<div class="searchrespond" id="searchRespond">
<h id="areaCovered">YES! We cover your area destination</h>
<h id="areaNotCovered">We don't cover your area destination yet
<p id="searchResult"></p>
</h>
<h id="fillArea">Please fill your area destination first</h>
</div>
</form>
</div>
</div>
suggest to validate input by making first letter uppercase and rest lowercase to match the array values
with javascript indexOf function
function searchRespond() {
var input = document.getElementById("myInput").value;
var area2search = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(); /* make fist letter capital and rest lower case to match array */
if (cities.indexOf(area2search) > -1) {
document.getElementById("areaCovered").style.display = "block";
//In the array!
} else {
document.getElementById("areaNotCovered").style.display = "block";
document.getElementById("searchResult").innerHTML = document.getElementById("myInput").value;
}
}
var cities = ["Banda Aceh", "Bandar Lampung", "Banyuwangi", "Bandung", "Bali", "Batam", "Batu", "Bekasi", "Bengkulu", "Binjai", "Blitar", "Bogor", "Bukittinggi", "Cimahi", "Cirebon", "Denpasar", "Depok", "Dumai", "Gunungsitoli", "Jakarta", "Jambi", "Kediri", "Langsa", "Lhokseumawe", "Lombok", "Lubuklinggau", "Madiun", "Magelang", "Malang", "Medan", "Metro", "Mojokerto", "Padang", "Padang Sidempuan", "Padangpanjang", "Pagar Alam", "Palembang", "Pangkal Pinang", "Pariaman", "Pasuruan", "Payakumbuh", "Pekalongan", "Pekanbaru", "Pematangsiantar", "Prabumulih", "Prigi", "Probolinggo", "Sabang", "Salatiga", "Sawahlunto", "Semarang", "Serang", "Sibolga", "Solo", "Subussalam", "Sukabumi", "Sumbawa", "Sungaipenuh", "Surabaya", "Surakarta", "Tangerang", "Tangerang Selatan", "Tanjungbalai", "Tanjungpinang", "Tasikmalaya", "Tebing Tinggi", "Tegal", "Yogyakarta"];

Javascript not creating spans as supposed to

I have a hardcoded span group to which I would like to add more spans from user input, I have tried to do this with a template and without but neither option works out for me
CSS:
.item { /*This is the style I want my new spans to inherit*/
display: flex;
align-items: center;
height: 48px;
line-height: 48px;
cursor: pointer;
padding-left: 24px;
}
.item:hover {
background-color: rgba(0, 0, 0, 0.04);
}
I'm trying to collect a user input from my modal to append it into my other spans which I hardcoded to see what it looks like for now
HTML:
<!------------------------------------------------------------- The modal from which i will be taking the input---------------------------------->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<form name="newLayerForm" onsubmit="return validateNewLayerName()" method="post" required>
<span class="close">×</span>
<p>Name your new Layer: </p>
<input placeholder="Type your desired layer name" type="text" name="newLayerName" id="newLayerName">
<button type="submit" value="submit" id="submitNewLayer" class="miro-btn miro-btn--primary miro-btn--small"
style="border: none; background-color: rgb(46,139,87); font-size: 15px; padding: 0px">Create</button>
</form>
</div>
</div>
<!----------------------------------------------------------------End of modal ------------------------------------------------------------------>
</div>
<template>
<div class="item item-layer"><span id="displayLayer"></span></div>
<span>sample layer 1</span>
<span>sample layer 2</span>
<!------------------------------------ template for the first function to add spans into ----------------->
</template>
<div class="miro-p-medium" style="font-size: 20px;">
<div class="item item-layer"><span id="displayLayer">sample layer 1</span></div>
<div class="item item-layer"><span>sample layer 2</span></div>
<div class="item item-layer"><span>sample layer 3</span></div>
<div class="item item-layer"><span>sample layer 4</span></div>
</div>
I have tried 2 ways to achieve this in my javascript code, 1 way with doing all of this inside a template and the other way to just use a div, at some point the input was being added when i appended it to body for about 1 second before disappearing, but I would also like the input from modal to inherit the same style and place in html as the 4 hardcoded spans I have right now
Javascript:
let template = document.querySelector('template').content
let layerTemplate = template.querySelector(".item-layer")
//modals
let modal = document.getElementById("myModal")
let btn = document.getElementById("btnCreate")
let span = document.getElementsByClassName("close")[0]
//function layerCreator(userInput) { // attempt with template
//let layerEl = layerTemplate.clondeNode(true)
//layerEl.querySelector("span").innerText = userInput
//document.getElementById("displayLayer").innerHTML = userInput
//return layerEl
//}
function layerCreatorX(input) { //attempt to directly insert into body
let x = document.createElement("span")
let t = document.createTextNode(input)
x.appendChild(t)
document.body.appendChild(x)
}
function validateNewLayerName() { // validates for empty input from input field
let input = document.forms["newLayerForm"]["newLayerName"].value
if (input == "" || input == null) {
alert("Cannot submit empty field, please try again!")
return false
}
else {
//this appends layer list with new layer
layerCreatorX(input)
}
}
I'm not too experienced in JS so I will be thankful for any suggestions or articles to look into
added just the most essential parts of the code, can add more if needed
Update: Forgot to include the function where i validate input from modal and use the function, it is now added in JS part
You are missing some key things:
You didn't post your validateNewLayerName function. This should return false, to avoid submitting the form.
You are not calling layerCreatorX and passing the value of newLayerName in the newLayerForm form.
You did not apply the class names item item-layer to the new span you created.
You are not adding the span to the .miro-p-medium container.
const template = document.querySelector('template').content
const layerTemplate = template.querySelector(".item-layer")
const modal = document.getElementById("myModal")
const btn = document.getElementById("btnCreate")
const span = document.getElementsByClassName("close")[0]
function validateNewLayerName() {
let input = document.forms["newLayerForm"]["newLayerName"].value
if (input == "" || input == null) {
alert("Cannot submit empty field, please try again!");
} else {
layerCreatorX(input);
}
return false; // Avoid submitting the form...
}
function layerCreatorX(input) {
const x = document.createElement("span");
const t = document.createTextNode(input);
x.className = 'item item-layer'; // Add the appropriate class.
x.appendChild(t);
document.querySelector('.miro-p-medium').appendChild(x);
// Let the modal window know that is can be closed now...
}
.item {
display: flex;
align-items: center;
height: 48px;
line-height: 48px;
cursor: pointer;
padding-left: 24px;
}
.item:hover {
background-color: rgba(0, 0, 0, 0.04);
}
.modal {
position: absolute;
border: thin solid grey;
background: #FFF;
padding: 0.5em;
right: 4em;
}
<div id="myModal" class="modal">
<div class="modal-content">
<form name="newLayerForm"
onsubmit="return validateNewLayerName()"
method="post" required>
<span class="close">×</span>
<p>Name your new Layer: </p>
<input type="text" id="newLayerName" name="newLayerName"
placeholder="Type your desired layer name">
<button type="submit" id="submitNewLayer" value="submit"
class="miro-btn miro-btn--primary miro-btn--small"
style="border: none; background-color: rgb(46,139,87); font-size: 15px; padding: 0px">Create</button>
</form>
</div>
</div>
<template>
<div class="item item-layer">
<span id="displayLayer"></span>
</div>
<span>sample layer 1</span>
<span>sample layer 2</span>
</template>
<div class="miro-p-medium" style="font-size: 20px;">
<div class="item item-layer"><span id="displayLayer">sample layer 1</span></div>
<div class="item item-layer"><span>sample layer 2</span></div>
<div class="item item-layer"><span>sample layer 3</span></div>
<div class="item item-layer"><span>sample layer 4</span></div>
</div>

Character counter showing within the input field

I have an input field and I want to be able to show the length of characters being typed in but I want it to be within the input box all the way to the end of the input box. I'm not even sure where to start to do this.
Not really sure where to start.
<label class="label is-capitalized">Description One </label>
<div class="field">
<div class="control is-expanded">
<input type="text" class="input size19" placeholder="description one" v-model="keyword">
</div>
<div>
var app = new Vue ({
el: '#app',
data: {
keyword: 'hello'
}
})
A counter within the input field pulled to the right edge
this can be handled in CSS in many ways
// Instantiating a new Vue instance which has preinitialized text
var app1 = new Vue({
el: '#app1',
data: {
keyword: 'hello'
}
});
.field {
margin: 1em;
}
.input {
padding-right: 30px;
}
.input-count {
margin: -30px;
opacity: 0.8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- App 2 -->
<div id="app1">
<div class="field">
<div class="control is-expanded">
<input type="text" class="input size19" placeholder="description one" v-model="keyword" />
<span v-if="keyword.length" class="input-count">{{keyword.length}}</span>
</div>
<div>
You'll have to use CSS to achieve this. Because you cannot get something like this within the input box:
some text in input 18
There has to another div overlapping your input box. See this:
var counter = document.getElementById ('counter'),
input = document.getElementById ('inp');
counter.innerHTML = input.value.length;
input.addEventListener ('keyup', function (e) {
counter.innerHTML = input.value.length;
});
.inline-block {
display: inline-block;
}
.relative {
position: relative;
}
.absolute {
position: absolute;
}
#counter {
top: 0;
right: 0
}
<div class='container'>
<label class="label is-capitalized">Description One </label>
<div class="field">
<div class="control is-expanded relative inline-block">
<input type="text" class='input' id="inp" placeholder="description one" />
<div id='counter' class='absolute'>
</div>
</div>
<div>
</div>
You can add additional styling if needed.
Try this
<div id="app1">
<br>
<div class="holder">
<label>
{{keyword.length}}
</label>
<input type="text" class="input size19" placeholder="description one" v-model="keyword">
</div>
CSS
holder {
position: relative;
}
.holder label {
position: absolute;
left: 200px;
top: 26px;
width: 20px;
height: 20px;
}
.holder input {
padding: 2px 2px 2px 25px;
}
Check the below fiddle for the solution
https://jsfiddle.net/zr968xy2/4/

Angular controller not loading on link click

I'm writing a page that has angular in it that responds to ajax requests and loads various data into a table. The angular works as expected when I type in the address, but if I use a link ( link ) to get to the page, the controller fails to load (but the html shows up). There are no page errors in the console except a resource not loaded for an image because the url is not being loaded by the angular. Here is my code:
<h1 style="text-align: center;">Product Search</h1>
<input type="text" class="form-control" placeholder="Search (Ex. ea-004, Christmas)..." id="search" style="margin-left: auto; margin-right: auto; margin-bottom: 15px;">
<div ng-app="search_results" style="text-align: center; margin-left: 0px; margin-right: 0px;">
<div ng-controller="search_results_ctl" style="text-align: center; margin-left: 0px; margin-right: 0px;">
product{{JSON.stringify(product)}}
<style>
.product:hover{
background-color: #DDDDDD;
cursor: pointer;
border:0px solid grey;
border-radius: 5px;
}
.product-selector:hover {
color: black;
}
</style>
<script>
var app = angular.module("search_results", ['angularUtils.directives.dirPagination']);
app.controller("search_results_ctl", ['$scope', function($scope){
console.log("Angular loaded...");
$scope.results = "";
$('#search').keypress(function(ev){
if(ev.which != 13){//do not add enter to search text, just submit query again
s_term = $('#search').val() + String.fromCharCode(ev.which);//append last character typed
}else{
s_term = $('#search').val();
}
$.ajax({
url: "/query",
data: {s_term: s_term},
success: function(data){
//console.log("products: " + data);
$scope.products = JSON.parse(data);
$scope.$apply();
}
});
});
}]);
</script>
<span ng-if="products != null">
<div style="width: 80%; margin: auto !important;
" dir-paginate="product in products | itemsPerPage: 10" class="row product">
<a href="/orders/new?product_id={{product.id}}" class="product-selector">
<div class="col-md-3 col-sm-3">{{product.title}}</div><div class="col-md-6 col-sm-6">{{product.description}}</div><div class="col-md-3 col-sm-3" style="text-align: center"><img src='{{product.image}}' width="50px" height="50px" style="margin-top: auto; margin-bottom: auto;"></div></a>
</div>
</span>
<span ng-if="products == null" >
<div style="background-color: #DDDDDD; border: 0px solid grey; border-radius: 5px;">
<h3 style="text-align: center;">Creating an Order</h3>
<p><strong>To start</strong>, type in the product code from the website or a key word like "christmas" or "sports". Click the product you would like to order, and it will take you to the order page.</p>
</div>
</span>
<dir-pagination-controls></dir-pagination-controls>
</div>
</div>
the link that is directing my to the page uses an href of "/products/search", which is the correct route.
Any help would be most appreciated!
Turns out after some further reading turbolinks was causing the problem. Turbolinks does not allow a full page reload, so angular never got fully bootstrapped. Here is a more thorough post on the issue: Using angularjs with turbolinks

javascript/jquery onChange function for div.text to update form hidden field value

My Classic ASP cart page uses divs for a quantity selector within a form:
<form action="/update-cart/" method="post">
<div class="quantity-selector detail-info-entry">
<div class="detail-info-entry-title">Quantity</div>
<div class="entry number-minus"> </div>
<div class="entry number">1</div>
<div class="entry number-plus"> </div>
</div>
</div>
</form>
when - or + is clicked the 1 will update as expected. the code to do this is this:
$('.number-plus').on('click', function(){
var divUpd = $(this).parent().find('.number'), newVal = parseInt(divUpd.text(), 10)+1;
divUpd.text(newVal);
});
$('.number-minus').on('click', function(){
var divUpd = $(this).parent().find('.number'), newVal = parseInt(divUpd.text(), 10)-1;
if(newVal>=1) divUpd.text(newVal);
});
What is the easiest way to post the content of the div with class "number" above when a form is submitted. Do i use:
<input type="hidden" id="Num" name="Num" value="" />
Or another way. Either way, how can this be done easily as I cannot get the variable "newVal" to populate the hidden field.
Thanks
This demo has 2 features of note.
The following are done with HTML and inline JS (e.g. onchange='...)
<input>s .number-minus and number-plus
<output> .number displays the sum of .number-minus and .number-plus
As requested, the sum of .number-minus and .number-plus is stored in a <input [hidden]> named .secret. This value was derived from <output> value by using jQuery (overkill IMO). `
$(function() {
$('#pos, #neg').on('change', function(event) {
var cnt = $('#counter').val();
$('#secret').val(cnt);
console.log('Secret: ' + secret.value);
});
});
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>javascript/jquery onChange function for div.text to update form hidden field value</title>
<meta name="description" content="SO33312004">
<style>
.detail-info-entry-title,
#pos,
#neg {
font-variant: small-caps;
}
.entry {
padding: 3px;
margin: 0 5px;
width: 48px;
line-height: 1.6;
border: 2px solid #00E;
border-radius: 8px;
display: table-cell;
}
#counter {
font-weight: 900;
margin: auto;
display: table-cell;
height: 24px;
}
#form33312004 {
color: #0CF;
background: hsla(180, 100%, 10%, 1);
width: 33%;
height: 30%;
text-align: center;
vertical-align: middle;
display: table-row;
}
.field {
width: 50px;
display: table-cell;
}
footer {
font-size: .75em;
text-align: center;
}
</style>
</head>
<!--http://stackoverflow.com/questions/33312004/javascript-jquery-onchange-function-for-div-text-to-update-form-hidden-field-val-->
<body>
<form id="form33312004" submit="return false" oninput="counter.value = parseInt(pos.value, 10) - parseInt(neg.value, 10)">
<fieldset class="quantity-selector detail-info-entry">
<legend class="detail-info-entry-title">Quantity</legend>
<div class="field">
<input type="number" id="pos" min="0" max="999" step="any" value="0" class="entry number-plus">
<label for="pos">Positive</label>
</div>
<output for='pos neg' id="counter" name="counter" class="entry number">0</output>
<div class="field">
<input type="number" id="neg" min="0" max="999" step="any" value="0" class="entry number-minus">
<label for="neg">Negative</label>
</div>
</fieldset>
<input id="secret" type="hidden">
</form>
<div class="field">
<footer>Observe the hidden input's value thru
<br/>the console. (<b>F12</b> then the <b>Console</b> tab).</footer>
<script sr="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"></script>
</body>
</html>
With pure JS:
document.getElementById("Num").value = < variable name >
With jQuery(not 100% sure)
$("Num").value(< variable name>)
So I solved the problem myself.
I added the following line:
$("#Num").val(newVal);
To both the jquery functions for the + and - divs as follows:
$('.number-plus').on('click', function(){
var divUpd = $(this).parent().find('.number'), newVal = parseInt(divUpd.text(), 10)+1;
divUpd.text(newVal);
$("#Num").val(newVal);
});
$('.number-minus').on('click', function(){
var divUpd = $(this).parent().find('.number'), newVal = parseInt(divUpd.text(), 10)-1;
if(newVal>=1) divUpd.text(newVal);
$("#Num").val(newVal);
});
I am sure I had tried this but after thought I may have omitted the $ at the beginning. Always something simple in the end

Categories