adding search bar through JavaScript - javascript

I have a working search bar that is added through the html. However to make the code unobtrusive i am trying to append the search bar and button through JavaScript. I am able to display the search bar and button, but the functionality of bringing up results has stopped working.
Here is the section to add the search bar in JS.
var $searchSection = $('<div class="student-search"></div>');
$searchSection.append('<input id = "search-criteria" placeholder="Search for students..."></input>');
$searchSection.append('<button>Search</button>');
//Append search section
$('.page-header').append($searchSection);
I am trying to get the functionality of search working. Here is a link to the code with the search working, as the search bar is included in the html. http://codepen.io/fun/pen/RRyaNm
This is a link to the code with search bar added through the js but with no search functionality. http://codepen.io/fun/pen/VjraNd?editors=1010
How do you get the search to work through adding from the js?
Any help or pointers would be awesome.
Thank you,
Harry

You don't have to add more function, just move your codes to the top. Check this
jsfiddle https://jsfiddle.net/xt5193z1/
//Search section
var $searchSection = $('<div class="student-search"></div>');
$searchSection.append('<input id = "search-criteria" placeholder="Search for students..."></input>');
$searchSection.append('<button>Search</button>');
//Append search section
$('.page-header').append($searchSection);
var $studentItem = $('.student-item');
var $pagination = $('.pagination');
var $searchCriteria = $('#search-criteria');
var perPage = 10;
// count number of student items
var studentCount = $studentItem.length;
// number of pages = number of students / 10 rounded up
var pageNumber = Math.ceil(studentCount / perPage);
// remove all student items
var initialTen = $studentItem.hide();
// display first 10 student items
initialTen = $studentItem.slice(0, perPage).show();
// pagination ul
var paginationHTML = '<ul>';
// calc number of links
for (var i = 1; i < pageNumber + 1; i++) {
// li and link for each page
paginationHTML += '<li>' + i + '</li>';
}
// end of ul
paginationHTML += '</ul>';
// display list to page
$pagination.html(paginationHTML);
// pagination link click
$('.pagination li a').on('click', function() {
// remove active
$('.pagination li a.active').removeClass('active');
// add active class
$(this).addClass('active');
// page number of clicked
var pageNum = this.text;
// Start point for slice
// e.g 3 * 10
var startFrom = pageNum * perPage - perPage;
// end point for slice
// e.g 30 + 10
var endOn = startFrom + perPage;
// display students based on number clicked
$studentItem.hide().slice(startFrom, endOn).show();
});
// Error message for no matches found
var $noMatches = $('<h2>No matches found please try again</h2>');
// Add to page
$('.page').append($noMatches);
// hide initially
$noMatches.hide();
// search box on type
$searchCriteria.on('input', function() {
// remove all result classes
$studentItem.each(function() {
$(this).removeClass("result");
});
// value of searched
var text = $(this).val().toLowerCase();
// results of search
var results = $("ul.student-list li:contains('" + text.toLowerCase() + "')");
results.addClass("result");
// show or hide based on result matching div
$studentItem.each(function() {
if ($(this).hasClass('result')) {
$(this).show("slow");
} else {
$(this).hide();
}
});
if (results.length > 10) {
// remove all student items
var initialTen = $studentItem.hide();
// display first 10 student items
initialTen = $studentItem.slice(0, perPage).show();
// show pagination
$('.pagination').show();
// hide no matches message
$noMatches.hide();
} else if (results.length === 0) {
$pagination.hide();
$noMatches.show();
} else {
$pagination.hide();
}
});

As Siguza said, $('#search-criteria') doesn't exist at the time you're fetching it. So, the on function is a good idea, but it should be given like this :
$('.page-header').on('input', '#search-criteria', function() {
//your code
});
What it does is , it will bind the function to the element that is added dynamically in DOM
Here is the jsFiidle
It will work for you. :)

Related

How to get checked rows' values from html table on a sidebar using GAS?

I have a table whose rows consist of 3 columns. 1º is a checkbox, 2º contains the colors and the 3º contains the hex.
As the user selects the colors desired by ticking the checkboxes, i imagine the colors being pushed into an arrat, that will be written to a cell as the user clicks on the save button.
I've borrowed this snippet from Mark, but it doesn't seem to run in my context:
var checkboxes = document.getElementsByTagName("input");
var selectedRows = [];
for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i];
checkbox.onclick = function() {
var currentRow = this.parentNode.parentNode;
var secondColumn = currentRow.getElementsByTagName("td")[1];
selectedRows.push(secondColumn);
};
console.log(selectedRows)
}
This is the javascript part running to load and populate the table and I'm not sure where the above snippet woud go into:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
/**
* Run initializations on sidebar load.
*/
$(function() {
// Assign handler functions to sidebar elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
google.script.run
.withSuccessHandler(function (record) { //<-- with this
showRecord(record);
})
.withFailureHandler(
function(msg, element) {
showStatus(msg, $('#button-bar'));
element.disabled = false;
})
.getRecord();
});
/**
* Callback function to display a "record", or row of the spreadsheet.
*
* #param {object[]} Array of field headings & cell values
*/
function showRecord(record) {
if (record.length) {
for (var i = 0; i < record.length-1; i++) {
// Adds a header to the table
if(i==0){
$('#sidebar-record-block').append($($.parseHTML('<div class="div-table-row"><div class="div-table-header">Sel</div><div class="div-table-header">Color</div><div class="div-table-header">Hex</div></div>')));
}
// build field name on the fly, formatted field-1234
var str = '' + i;
var fieldId = 'field-' + ('0000' + str).substring(str.length)
// If this field # doesn't already exist on the page, create it
if (!$('#'+fieldId).length) {
var newField = $($.parseHTML('<div id="'+fieldId+'"></div>'));
$('#sidebar-record-block').append(newField);
}
// Replace content of the field div with new record
$('#'+fieldId).replaceWith('<div id="'+fieldId+'" class="div-table-row"></div>');
$('#'+fieldId).append('<input type="checkbox" class="div-table-td" id=CB"'+fieldId+'"name="checkBox" </input>')
.append($('<div class="div-table-td">' + record[i].heading + '</div>'))
.append('<div class="div-table-td">' + record[i].cellval + '</div>')
}
}
}
</script>
Sample of how to get the checked tickboxes an button click
Assuming all your checkboxes are tied to a row, you can loop through all checkboxes with a query selector,
access their checked status
and save the indices of those checkboxes.
Those indices will be the same as when looping through the corresponding table rows.
Sample implementing a button click event:
var saveButton = document.getElementById("myButtonId");
saveButton.onclick = function(){
var checkedRowIndices = [];
$('input[type=checkbox]').each(function( index ) {
if($(this)[0].checked{
checkedRowIndices.push(index);
}
});
};
//now get the rows with those indeices and do something with them

How to restore removed item from array?

I have a users card list, my task is:
Clicking "undo" button: will restore the last card that was deleted (use array)
Question 1: How to make array from cards list I have displayed ?
Question 2: How to restore the last card that was deleted?
(IF 2 cards are removed, "undo" button will to restore card one by one)
Link to codepen here https://codepen.io/MarinaShumeiko/pen/Nbeqew?editors=1010
var root = 'https://jsonplaceholder.typicode.com';
var notificationMessage = "Oops, there are no more user cards to display";
var userIndex = 0;
var undoBtn = $("#button")
var $clearBtn = $("#clear");
var $contentArea = $("#content");
var cardTemplate = '<div class="card" data-id="{id}"><div class="title"><div class="image"></div><div class="name">{name}</div><button onclick="removeUser({postid})" class="close"></button></div><div class="description">{body}{email}</div></div>';
// - Load all the card at once, when screen load
$(function() {
$contentArea.append(renderUser);
});
// Make array from usercards
var $cardDiv = $(".card");
var usersCardArray = $cardDiv.toArray(); // return usersCardArray.length = 0 :(
//remove all card at once
$clearBtn.click(clearUsers);
function clearUsers () {
$contentArea.empty();
userIndex = 0;
}
//remove one card
$('.card .close').on('click', removeUser);
function removeUser(postId) {
$('[data-id="' + postId + '"]').remove();
}
// get user data
function getUser () {
return $.ajax({ url: root + '/posts/1/comments', method: 'GET' });
}
function renderUser() {
getUser().then(function (user) {
for (var i = 0; i = user.length; i++) {
var card = cardTemplate
.replace('{id}', user[userIndex].id)
.replace('{postid}', user[userIndex].id)
.replace('{name}', user[userIndex].name)
.replace('{body}', user[userIndex].body)
.replace('{email}', user[userIndex].email);
$contentArea.append(card);
userIndex++;
}
})
}
Since you don't manipulate any actual data, only the view itself - you can add class .hidden on delete card, and remove this class on undo.
To keep track on deleted users I added array var deletedUsers =[]. Each time you delete a user, add its id to array and hide it from view by adding class hidden.
On undo - pop the user id from deletedUsers, and remove class hidden from this user's card
https://codepen.io/anon/pen/PbXxrB

How can I make sure that my directory listing sorts in alphabetical order when it displays the items with javascript?

I have a javascript that should displays items like this image:
But it is not generating them in a alphabetical order like the image.
Here is a example how it is(only HTML & CSS included, its shows basicly how its rendered after the javascript has been executed):
Take a look at: http://jsbin.com/UHiZUJU/20/edit
The javascript that generates these items with its Big letter is following:
$(".processlinks-section-item-title2 a").each(function() {
var text = $(this).text();
var href = $(this).attr('href');
if (!text.length) return;
var letter = text.substr(0, 1).toUpperCase();
if (letter.match(/[0-9]/g))
letter = "#";
var list = $('.processlinks-section-template');
var section = list.children('[data-letter="'+letter+'"]');
if (!section.length) {
var section = $('<div class="processlinks-section-item" data-letter="' + letter + '"></div>');
if (!list.children().length) {
list.append(section);
} else {
// find right element so list is sorted
section.insertAfter(list.children()[0]);
}
}
var item = $('<div class="processlinks-section-item-title">' + '' + text + '');
if (!section.children().length) {
section.append(item);
} else {
// find right element so list is sorted
item.insertAfter(section.children()[0]);
}
});
So my question is how can I sort these in alphabetical order?
Here is a testing JSbin where CSS,HTML and javascript is included but the javascript executes on button click, its just for testing.
Take a look at: http://jsbin.com/aMElAba/5/edit
Sort the items before using each:
$(".processlinks-section-item-title2 a").sort(function(a, b) {
var letterA = $(a).text().charAt(0).toUpperCase(),
letterB = $(b).text().charAt(0).toUpperCase();
return letterA > letterB ? -1 : (letterA < letterB ? 1 : 0);
}).each(...

Generate page numbers using javascript/jquery?

How to generate page numbers like the below using javascript/jquery?
If the 5 th page is selected i have to show 3,4 and 6,7 and also 1,last page with prev,next...
Any suggestion....
EDIT:
How to work with json data that use these pagination div? (ie) My json data contains 50 records
I want to 10 in page 1 and so on... How to paginate json data with these numbers...
I want a jquery function to pass currentpageno,lastpagenumber and the function should generate me page numbers like the below for me
If it is the first page
If it is in the middle,
If it is the last page,
Second EDIT:
I have tried this function but doesn't seem to get the desired result
function generatePages(currentPage, LastPage) {
if (LastPage <= 5) {
var pages = '';
for(var i=1;i<=5;i++)
{
pages += "<a class='page-numbers' href='#'>" + i + "</a>"
}
$("#PagerDiv").append(pages);
}
if (LastPage > 5) {
var pages = '';
for (var i = 1; i <= 5; i++) {
pages += "<a class='page-numbers' href='#'>" + i + "</a>"
}
$("#PagerDiv").append(pages);
}
}
I have the lastPage and currentPage values please help me out getting this...
What you are looking for is called "pagination" and there's (as always) a jQuery plugin that does the job for you:
http://d-scribe.de/webtools/jquery-pagination/demo/demo_options.htm
(Download it here)
Edit: Since you don't seem to be able to get it working, here is one way (of several different) how you can use the plugin.
Step 1: Generate markup from your JSON-data like the following:
<div id="display">
<!-- This is the div where the visible page will be displayed -->
</div>
<div id="hiddenData">
<!-- This is the div where you output your records -->
<div class="record">
<!-- create one record-div for each record you have in your JSON data -->
</div>
<div class="record">
</div>
</div>
The idea is to copy the respective record to the display div when clicking on a page-link. Therefore, the plugin offers a pageSelect-callback function. Step 2 is to implement this function, for instance:
function pageselectCallback(pageIndex, jq){
// Clone the record that should be displayed
var newContent = $('#hiddenData div.record:eq('+pageIndex+')').clone();
// Update the display container
$('#display').empty().append(newContent);
return false;
}
This would mean that you have one page per record. If you want to display multiple records per page, you have to modify the above function accordingly.
The third and final step is to initialize the whole thing correctly.
function initPagination() {
// Hide the records... they shouldn't be displayed
$("#hiddenData").css("display", "none");
// Get the number of records
var numEntries = $('#hiddenData div.result').length;
// Create pagination element
$("#pagination").pagination(numEntries, {
num_edge_entries: 2,
num_display_entries: 8, // number of page links displayed
callback: pageselectCallback,
items_per_page: 1 // Adjust this value if you change the callback!
});
}
So, you just have to generate the HTML markup from your JSON data and call the init-function afterwards.
It's not that difficult, is it?
yeah #SLaks is right. nothing too crazy here. You will have 2 variables currentPageNumber and lastPageNumber.
$("div.paginator").append("<a...>prev</a>");
$("div.paginator").append("<a...>1</a>");
for (x = (currentPageNumber - 2; x <= (currentPageNumber + 2); x++) {
$("div.paginator").append("<a...>"+ x +"</a>");
}
$("div.paginator").append("<a...>"+ lastPageNumber +"</a>");
$("div.paginator").append("<a...>next</a>");
// you could apply styles to and a tag in the div.paginator
// you could apply a special class to the a tag that matches the currentPageNumber
// you can also bind some click events to each a tag and use the $(this).text() to grab the number of the page to go to
Use THIS or THAT plugin. They're both easy html pagination plugins. Put everything in the html at once and paginate with one of those.
Add two new hidden inputs
<input type='hidden' id='current_page' />
<input type='hidden' id='show_per_page' />
Next add an empty div to create pagination controls
<!-- An empty div which will be populated using jQuery -->
<div id='page_navigation'></div>
$(document).ready(function(){
//how much items per page to show
var show_per_page = 5;
//getting the amount of elements inside content div
var number_of_items = $('#content').children().size();
//calculate the number of pages we are going to have
var number_of_pages = Math.ceil(number_of_items/show_per_page);
//set the value of our hidden input fields
$('#current_page').val(0);
$('#show_per_page').val(show_per_page);
//now when we got all we need for the navigation let's make it '
/*
what are we going to have in the navigation?
- link to previous page
- links to specific pages
- link to next page
*/
var navigation_html = '<a class="previous_link" href="javascript:previous();">Prev</a>';
var current_link = 0;
while(number_of_pages > current_link){
navigation_html += '<a class="page_link" href="javascript:go_to_page(' + current_link +')" longdesc="' + current_link +'">'+ (current_link + 1) +'</a>';
current_link++;
}
navigation_html += '<a class="next_link" href="javascript:next();">Next</a>';
$('#page_navigation').html(navigation_html);
//add active_page class to the first page link
$('#page_navigation .page_link:first').addClass('active_page');
//hide all the elements inside content div
$('#content').children().css('display', 'none');
//and show the first n (show_per_page) elements
$('#content').children().slice(0, show_per_page).css('display', 'block');
});
function previous(){
new_page = parseInt($('#current_page').val()) - 1;
//if there is an item before the current active link run the function
if($('.active_page').prev('.page_link').length==true){
go_to_page(new_page);
}
}
function next(){
new_page = parseInt($('#current_page').val()) + 1;
//if there is an item after the current active link run the function
if($('.active_page').next('.page_link').length==true){
go_to_page(new_page);
}
}
function go_to_page(page_num){
//get the number of items shown per page
var show_per_page = parseInt($('#show_per_page').val());
//get the element number where to start the slice from
start_from = page_num * show_per_page;
//get the element number where to end the slice
end_on = start_from + show_per_page;
//hide all children elements of content div, get specific items and show them
$('#content').children().css('display', 'none').slice(start_from, end_on).css('display', 'block');
/*get the page link that has longdesc attribute of the current page and add active_page class to it
and remove that class from previously active page link*/
$('.page_link[longdesc=' + page_num +']').addClass('active_page').siblings('.active_page').removeClass('active_page');
//update the current page input field
$('#current_page').val(page_num);
}

Warning: Unresponsive Script error?

Hey, my script seems to be getting this warning message whenever I run it.
This happens when I call a jquery function in the script. I have included the script below and put - Warning: Unresponsive Script - comment where I called the function. I don't really know why I'm getting the warning message.
Here is the project Im working on, if you want to see it Click Here
I am trying to update the pagination numbers when filter options are selected. So when you select the color 'yellow' you get one result, which is 'giant' and there should only be 1 page number displayed as opposed to the 4.
If anyone has any ideas to get this working properly that would be amazing. Thanks.
JQuery Script:
<script>
$(document).ready(function(){
function paginateIt(){
//how much items per page to show
var show_per_page = 3;
//getting the amount of elements inside content div
var number_of_items = $('#content ul').filter(":not(.hidden)").children().size();
//calculate the number of pages we are going to have
var number_of_pages = Math.ceil(number_of_items/show_per_page);
//set the value of our hidden input fields
$('#current_page').val(0);
$('#show_per_page').val(show_per_page);
//now when we got all we need for the navigation let's make it '
/*
what are we going to have in the navigation?
- link to previous page
- links to specific pages
- link to next page
*/
var navigation_html = '<a class="previous_link" href="javascript:previous();">Prev</a>';
var current_link = 0;
while(number_of_pages > current_link){
navigation_html += '<a class="page_link" href="javascript:go_to_page(' + current_link +')" longdesc="' + current_link +'">'+ (current_link + 1) +'</a>';
current_link++;
}
navigation_html += '<a class="next_link" href="javascript:next();">Next</a>';
$('#page_navigation').html(navigation_html);
//add active_page class to the first page link
$('#page_navigation .page_link:first').addClass('active_page');
//hide all the elements inside content div
$('#content ul').filter(":not(.hidden)").children().css('display', 'none');
//and show the first n (show_per_page) elements
$('#content ul').filter(":not(.hidden)").children().slice(0, show_per_page).css('display', 'block');
// Start filter script
(function($) {
$.fn.randomize = function(){
return $(this).sort(function() {return 0.5 - Math.random()});
}
$.fn.filterprojects = function(settings) {
settings = $.extend({
animationSpeed: 900,
animationPulse: 100,
animationEase: "linear",
activeClass: "active",
allTag: "all",
randomize: true,
show: { width: "show", opacity: "show" },
hide: { width: "hide", opacity: "hide" },
filterTagSelector: [] // specify at least one
}, settings);
$(this).each(function(i, o){
var _elements = $(this).children();
/* Binding the filter */
$(this).bind("filter", function(){
var _groups = [];
var _filtered_elements = _elements;
$.each(settings.filterTagSelector, function(k, j){
_groups[k] = [];
$(this + "." + settings.activeClass).each(function(){
if(!$(this).hasClass(settings.allTag) && this.hash != undefined) { _groups[k].push(this.hash.substring(1)); }
});
if(_groups[k].length > 0){
_filtered_elements = _filtered_elements.filter("." + _groups[k].join(",."));
}
});
/* Randomize */
if(settings.randomize){
_filtered_elements = _filtered_elements.randomize();
_elements = _elements.randomize();
}
/* Show */
_filtered_elements.each(function(i,o){
$(this).queue(function(){
$(this).animate({left: "+0"}, (settings.animationPulse*i)); // dirty trick :)
$(this).animate(settings.show, settings.animationSpeed);
$(this).dequeue()
});
});
/* Hide */
_elements.not(_filtered_elements).each(function(i,o){
$(this).queue(function(){
$(this).animate({left: "+0"}, (settings.animationPulse*i)); // dirty trick :)
$(this).animate(settings.hide, settings.animationSpeed);
$(this).dequeue()
});
});
});
/* Setup filter selectors */
$.each(settings.filterTagSelector, function(k, j){
$(""+this).click(function(e){
e.preventDefault();
if($(this).hasClass(settings.allTag)){
$(j).removeClass(settings.activeClass);
$(this).addClass(settings.activeClass);
} else {
$(this).hasClass(settings.activeClass) ? $(this).removeClass(settings.activeClass) : $(this).addClass(settings.activeClass);
$(j+"."+settings.activeClass).length > 0 ? $(j+"."+settings.allTag).removeClass(settings.activeClass) : $(j+"."+settings.allTag).addClass(settings.activeClass);
}
/* Triggering the filter */
$(o).trigger("filter");
})
});
});
return this
};
// Warning: Unresponsive Script
paginateIt();
})(jQuery); // End filter script
} // End PaginateIt script
paginateIt();
}); // End of JS script.
function previous(){
new_page = parseInt($('#current_page').val()) - 1;
//if there is an item before the current active link run the function
if($('.active_page').prev('.page_link').length==true){
go_to_page(new_page);
}
}
function next(){
new_page = parseInt($('#current_page').val()) + 1;
//if there is an item after the current active link run the function
if($('.active_page').next('.page_link').length==true){
go_to_page(new_page);
}
}
function go_to_page(page_num){
//get the number of items shown per page
var show_per_page = parseInt($('#show_per_page').val());
//get the element number where to start the slice from
start_from = page_num * show_per_page;
//get the element number where to end the slice
end_on = start_from + show_per_page;
//hide all children elements of content div, get specific items and show them
$('#content ul').filter(":not(.hidden)").children().css('display', 'none').slice(start_from, end_on).css('display', 'block');
/*get the page link that has longdesc attribute of the current page and add active_page class to it
and remove that class from previously active page link*/
$('.page_link[longdesc=' + page_num +']').addClass('active_page').siblings('.active_page').removeClass('active_page');
//update the current page input field
$('#current_page').val(page_num);
}
</script>
Unresponsive Script Fix
It looks like you're just calling paginateIt recursively. The paginateIt function does a bunch of work and then calls itself again, infinitely.
To fix this, remove the call to paginateIt() just below your comment "Warning: Unresponsive Script" comment.
Here's the simplified structure of your code so that you can see the problem more clearly:
function paginateIt(){
// Start filter script
(function($) {
$.fn.filterprojects = function(settings) {
$(this).each(function(i, o){
/* Binding the filter */
/* Setup filter selectors */
});
};
// Warning: Unresponsive Script
paginateIt();
})(jQuery); // End filter script
} // End PaginateIt script
paginateIt();
Re-pagination Fix
I would have written this line of code:
//getting the amount of elements inside content div
var number_of_items = $('#content ul').filter(":not(.hidden)").children().size();
as this:
var number_of_items = $('#content ul').children().filter(":visible").length;
Also, you'll want to call paginateIt after the animation completes for that to work correctly. You'll probably want to do this in an animation callback, but here's a temporary workaround:
/* Triggering the filter */
$(o).trigger("filter");
setTimeout(paginateIt, 1500);

Categories

Resources