Mobile first when using match media? - javascript

I have a page that uses multiple form elements. Far too many for a smartphone without scrolling, which I don't want. To solve this problem, I put the form elements in a carousel.
When I don't need the carousel (larger displays) I need to eliminate it. The only way I know of to do this is to reassign the parent properties of the carousel items and then remove the carousel.
This approach works fine using java-script. However, to pull this off I would need to use match media to call the java-script functions. Since most legacy browsers (which don't support match media) are used by desktops wouldn't this go against mobile first development?
Would it be wiser to design for legacy browsers and then upgrade the page for newer, more robust devices that can understand more updated languages or am I approaching this problem entirely wrong? I would rather not add a polyfill to fix this problem if I don't have to. Forgive my ignorance if I'm not seeing the simple solution here.
Here is a snippet that changes the parent div for large displays at codepen.
// Transfer elements from carousel to a larger div display
function SetParentDiv() {
var newParent = document.getElementById('LargeDisplayPage');
var oldParent = document.getElementById('1');
// Carousel items are 3 divs with numbered id's
for (var x=1; x < 4; x++) {
oldParent = document.getElementById(x);
while (oldParent.childNodes.length > 0) {
newParent.appendChild(oldParent.childNodes[0]);
}; ///endwhile
}; // endfor
document.getElementById('SmallDevicePage').style.display = 'none';
...
Here is the full Code Pen

Related

Trigger .click() on a link on mobile view only

So I'm currently working on a WordPress website with a Table of Contents plugin. All the plugin do is just detect headings and add them to its contents.
What I am trying to achieve on my current website (https://staging.vladesplana.com/planning-center-vlad-test) is that when the Window is at <= 768px, it should simulate a "click" event on the [ Collapse ] anchor link so that the Contents will be hidden on mobile load and only be Expanded when on Desktop pixels (1280px, etc) load
function tocToggle2() {
if (window.innerWidth <= 768) {
document.getElementsByClassName('lwptoc_toggle_label').click();
}
}
window.onload = tocToggle2;
May I know your thoughts or the proper code for this? I mainly just build websites on Elementor and know only basic Javascript.
Tried a few things as well from my searches and on Stack to no avail.
I use Custom CSS & JS plugin to insert CSS and JS codes into my WordPress website so please, no JQueries
EDIT: Corrected some of the codes.
Oh I think I got it.
I just added [0] on this line:
document.getElementsByClassName('lwptoc_toggle_label')[0].click();
Source:
https://www.geeksforgeeks.org/click-method-not-working-and-console-returns-an-error-message-in-javascript/#:~:text=click%20is%20not%20a%20function,you%20have%20written%20a%20document.
Since it says there:
If you spelled it correctly then probably this error arises because you are not aware that document.getElementsByClassName returns an array of elements, not a single element. In order to avoid the error, you need to access a single element and then perform a click().
I checked in the console as well to check if the function is working as intended but it throws an error there.
final code:
function tocToggle2() {
if (window.innerWidth <= 768) {
document.getElementsByClassName('lwptoc_toggle_label')[0].click();
}
}
Instead of using getElementsByClassName, which will give you a list with every matching element, use querySelector, which will return the first one it finds.
The reason your code isn’t working is because you can’t trigger a click on a list of nodes.

Capitalise HTML Element Targeted by CSS Selectors Using jQuery

In line with previous questions, I have another jQuery problem that's doing my head in.
I have an Elementor widget that's outputting a list of attributes that I'm using as a filterable list, so basically, it's a bunch of a tags inside li's.
The problem is, these are being pulled from a different system (long story, not relevant to the question) and it is passing them across in all caps. I want them displaying as capitalised, but because of the nature of text-transform, CSS can't help me.
I've used text-transform to make them all lower case, and now I just want to use jQuery to capitalise them. It needs to be every word as some entries have multiple words in them. However, I'm not getting any results.
The css selectors needed to target the a tags are as follows:
.woocommerce-widget-layered-nav-list__item.wc-layered-nav-term a
I've tried loads of different scripts and messed with them for a good hour or two now and managed to get rid of errors (like $ is not a function) but cannot get the text to captialise.
I've mostly been trying exampls from [this thread][1].
Here is what I think is the closest I've come:
<script>
jQuery.fn.capitalize = function() {
jQuery(this[0]).keyup(function(event) {
var box = event.target;
var txt = $(this).val();
var stringStart = box.selectionStart;
var stringEnd = box.selectionEnd;
jQuery(this).val(txt.replace(/^(.)|(\s|\-)(.)/g, function($word) {
return $word.toUpperCase();
}));
box.setSelectionRange(stringStart , stringEnd);
});
return this;
}
</script>
<script>
jQuery('.woocommerce-widget-layered-nav-list__item.wc-layered-nav-term a').capitalize();
</script>
I'm fully aware that it's not structured particularly well and I know it can be neater, but I have tried numerous ways around it to no avail.
This code is currently being run from a HTML widget in the Elementor archive template where this list appears.
I'd really appreciate it is someone could point out the probably really obvious problems so I can learn from how dumb I'm being.
Many thanks.

Image for <option> not working in IE

My requirement is to add images inside <option>. I have used the below code to display images in FF.
[Script]
var items = $("#ShipCountry option").children(); //dropdown options
for (i = 0; i < items.length; i++) {
$(items[i]).html("<img src='/Images/" + $(items[i]).html() + ".gif'></img>"); // adding image
}
This code works in FF but not in other browsers. I do not want to implement this logic using CSS as i need to display large number of images (options).
Is that possible without CSS for all browsers?
There is no way to make this work cross-browser, as lots of browsers restrict what you can do with the <option> tag. I'm surprised it works in Firefox to be honest. You might want to look into Select2 which makes this possible cross browser, and has great documentation.

Deeplinking div blocks

I am looking for a way to deep link div blocks. On a particular page I might have several div blocks each with its own contents. One of this blocks is visible, others are hidden. Once a link or a button is pressed the corresponding div is shown and others are hidden. Here is the HTML for the divs:
<div id="6ba28aae2dae153a1686cfee276632d8" class="page-block" style="display: block;">
<p>
1st block.
</p>
</div>
<div id="55cead0effa915778913d8667d0ae3a9" class="page-block" style="display: none;">
<p>
2nd block.
</p>
</div>
And here is the JavaScript used to switch the blocks.
/* Hide and show necessary blocks. */
function switchBlocks(UID)
{
var blocks = $('div.page-block');
for (i=0; i<blocks.length; i++)
{
if (blocks[i].id == UID)
{
blocks[i].style.display= 'block';
// Get the current URL and split it at the # mark
urlArray = window.location.href.split("#");
// Select the part before #
subURL = urlArray[0];
// Create a fake URL by adding UID to subURL
history.pushState(null, null, subURL + '#' + UID);
}
else
{
blocks[i].style.display= 'none';
}
}
}
What I am trying to do now is assign each block its unique URL by using the blocks ID. I am able to update the URL with the relevant ID yet can't figure out how to link the particular URL to a specific block so that the corresponding block is shown when accessing its URL.
I have studying the tutorial on the HTML5 History API but can't quite figure out how to apply it to my case.
if(window.location.hash == "#55cead0effa915778913d8667d0ae3a9")
{
$("div.page-block").hide();
$("div#55cead0effa915778913d8667d0ae3a9").show();
}
or
hash_id = window.location.hash;
if(hash_id.length > 0)
{
$("div.page-block").hide();
$(hash_id).show();
}
I think it is better to add and remove classes then having the desired css effect. I believe this is more efficient but I could be wrong.
You could also store a reference to the old div that is being shown so that you could just hide that one and show the other rather then iterating over an entire list of divs. In reality you only need to show one div and hide one div.
As far as browser history support. Do you need this to be cross browser supported? html5 history API is not supported in all browsers. This may not be a problem or concern for you.
List of supported browsers
http://caniuse.com/#search=history
I have used jquery bbq to add history support to a web application. It works well in older browsers.
http://benalman.com/projects/jquery-bbq-plugin/
For big javascript projects Backbone.js is the way to go it has browser history support as well as many other helpful built in functions that make it easy to manage your code base.

How can I handle a list with several hundred items in HTML? (Using Javascript)

I am creating a web page which is designed for mobile safari, and I create a list dynamically. The list is created from a text file in which I receive information and I append this information to the list. It works fine when there are about 200 items, but when the file is very large, (I have tried with up to 4000 items) the page becomes very slow, scrolling and selecting this items is very hard. I know I should not create so much HTML elements, but I am looking for a way to create a shorter list and replace the information on the list's elements depending on how much scrolling you have done. Any Ideas?
Clarification
To keep things simple I will consume right from the start the possibility of using a specialized JavaScript UI library. Personally I would not use such a solution since getting involved with a library creates additional constrains (and possibly bloat) to your project (unless you are working on a project that relies heavily on client-side UI components, in which case you should choose one UI library and stick with it).
Also, I will not consider "scrolling" as a solution (i.e. creating an endless list of DOM objects and simply scrolling through them). IMHO that is not really a "solution" to the problem, it is simply a method of generating the problem that led you here.
Think flow
You have to keep in mind that on the client side, the JavaScript language is in a sense "attached" to the browser's Document Object model. Your JavaScript code is practically "telling" the browser to modify the DOM hierarchy in a myriad of ways, and then the browser conforms. This is the main reason why pure JavaScript code tends to run fast and then things slow down dramatically when starting to manipulate DOM objects.
The main rule to follow, in my opinion, is to minimize as much as humanly possible the amount of DOM object manipulation by following this flow:
If possible, do it server-side: this can prove to be a very consistent and reliable solution; if your project allows for this, you should only send reasonably-sized segments of the data to the browser at any single time (e.g. one page from the entire set), this will allow the client to properly display and manipulate that data in a speedy and responsive way.
If you must do it on the client-side, avoid touching the DOM as much as possible: this is essential; if you receive 4000 objects in a JS script, keep them in memory, don't rush to translate all those elements into DOM objects; that's a death sentence.
Only manipulate the DOM at the last possible moment and touching the least amount of objects: since modifying the DOM takes a lot of effort (compared with other in-memory operations). Another danger here is memory leaking (browsers aren't perfect), since when creating and discarding many DOM objects, some of those discarded object might still survive in memory, thus producing a memory leak (which could eventually hog the browser or even the system).
Solutions
These are the approaches on the table:
Server-side pagination: perhaps this is obvious, but too many times people try to overlook this option, and I think that's wrong. Again, if your projects allows this, it is very difficult for such a solution to fail you: it can be very consistent and reliable (which is why it is a classic).
Client-side pagination: Obviously you could send the entire data to the browser, handle it in JS and then display it in reasonably-sized chunks at once, never exceeding a certain amount of generated DOM objects. This might seem attractive and more simple than Solution 1, however, beware that if your data is bidirectional (i.e. implies intervention and feedback from the user that must return to the server) and important (e.g. more important that statistical/reporting data that only needs to be displayed), you should probably avoid this option.
The reason is that even if JavaScript is fast and efficient enough to juggle this data in memory, it is not as safe; you never know what might happen client-side: the memory could get corrupted, the browser might crash etc.; basically you have no reasonable guarantee for your data. A server is better prepared to handle important data. What's more, it will be very difficult to have history navigation between pages and URL addresses that go to specific pages within the data-set (both are possible but not without a headache anyway).
Client-side dynamic scrolling: instead of displaying the objects from JS memory as full pages, you simply show a reasonable sub-set, let's say 100 items and then scroll down by taking one object (or more) from the top and moving it to the bottom of the list, altering it's contents accordingly. Obviously this option presents the same dangers as Solution 2, but it is still a very good solution.
Example
Considering that your projects works for mobile devices I consider the last approach as probably more feasible to you, so here is a (very) simplistic example of how it might be done using MooTools (obviously the principle can be applied using any framework):
<html>
<head>
<title>Endless scrolling example.</title>
<!-- Include the MooTools framework. -->
<script type="text/javascript" src="mootools-1.2.4-core-yc.js"></script>
<!-- Note: we'll use id's to select objects since it's faster. -->
</head>
<body>
<!-- Scroll up. -->
Up!
<!-- The list (i.e. container). -->
<ul id="list_container">
</ul>
<!-- Scroll down. -->
Down!
</body>
<!-- Our script. -->
<script type="text/javascript">
window.addEvent('domready', function() {
// database
var list = {};
// options
var list_size = 5000; // total list size
var list_offset = 0; // initial list position
var list_subset = 40; // the smount of displayed items
var scroll_step = 10; // items to scroll in one step
var time_delay = 50; // time delay between scroll steps
// make dummy items
for (var i = 0; i < list_size; i++) {
var red = Math.floor(i * 2) % 256;
var green = Math.floor(i * 3) % 256;
var blue = Math.floor(i * 4) % 256;
list[i] = "<span style=\"color:rgb(" + red + ", " + green + ", " + blue + ");\">" +
"My name is 'Object no." + (i + 1) + "'." +
"</span>";
}
// get container
var list_container = $('list_container')
// generate DOM objects
for (var i = 0; i < list_subset; i++) {
list_container.grab(new Element('li', { html: list[i] }));
}
// Up scroller.
function up() {
// check end
if (list_offset <= 0) {
return false;
}
// get element
var element = list_container.getLast();
// devance offset
list_offset--;
// re-write element
element.set('html', list[list_offset]);
// move top element to top
list_container.grab(element, 'top');
// success
return true;
}
// Down scroller.
function down() {
// check end
if (list_offset >= list_size - list_subset) {
return false;
}
// get element
var element = list_container.getFirst();
// advance offset
list_offset++;
// re-write element
element.set('html', list[list_offset + list_subset - 1]);
// move top element to bottom
list_container.grab(element, 'bottom');
// success
return true;
}
// Repeater function.
function repeater(direction) {
for (var i = 0; i < scroll_step; i++) {
// scroll
if (direction() == false) {
// deactivate repeater
$clear(list.scroll_period);
}
}
}
// configure up scroll
$('list_up_button').addEvents({
// activate scroll
'mouseenter': function() {
list.scroll_period = repeater.periodical(time_delay, null, up);
},
// deactivate scroll
'mouseleave': function() {
$clear(list.scroll_period);
}
});
// configure up scroll
$('list_down_button').addEvents({
// activate scroll
'mouseenter': function() {
list.scroll_period = repeater.periodical(time_delay, null, down);
},
// deactivate scroll
'mouseleave': function() {
$clear(list.scroll_period);
}
});
});
</script>
Sorry for the rather long code... hope it helps.
Instead of appending the items to the list, how about displaying up to 200 at once, then replacing the current items on a scroll forward - scroll back motion? You could use innerHTML for this, or DOM methods that create the elements.
You could create something like "virtual scrolling" - show only a few items (that can be viewed on the screen) and make the scrollbar appear by offsetting them with margins. This way, you'll have the user think he has 4000 items on the screen and have only 20 items in memory.
Use a dataTable. Two I know of are YUI2 dataTable and www.dataTables.net. I use www.dataTables.net because it's really nice and I'm quite used to it so far (not an expert though). You can use server-side processing which you can use to call a php file or method or other javascript, but it will grab x number of records for you and know where to start when you paginate through (pagination is already provided with the dataTable.
You'd instantiate the table like so:
<script type="text/javascript" char="utf-8>
$(document).ready(function() {
$('#tableName').dataTable({
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "php_filename.php",
"sPaginationType": "full_numbers"
});
});
</script>
That's an example image of what it would look like. The only issue with doing server-side processing is you'd have to pass the information in JSON format.
"aaData": [
"info1",
"info2",
etc...
]
Controls can be added as well into the aaData records. Here is a good example. Hope this helps.
Update 2:
You will have to download the jQuery file (1.4.1 is the version I used) and you'll have to reference the jQuery file, the dataTable.js file, and the css. The class name of the table will have to be "display". The css name is demo_table.css.
<script type="text/javascript" language="javascript" src="../Scripts/jquery-1.4.1.js"></script>
<script type="text/javascript" language="javascript" src="../Scripts/jquery.dataTables.js"></script>
<style type="text/css" title="currentStyle">
#import "../../Content/stylesheets/demo_table.css"
</style>
Even if you want to render the entire big list at one go, use a document fragment

Categories

Resources