How can I show a "loader" during knockout.js initialization? - jquery-mobile

I have a single-page web-app built with knockout.js and jQuery Mobile.
The view-model initialization (i.e. the ko.applyBindings() function) takes about 7-8 seconds. During this time, the page shows blank.
$(document).ready(function () {
ko.applyBindings(viewModel);
})
Is there a way to show the JQM loader in the meantime, or to show a kind of "splash screen", to give to the user a feedback that the "page is loading"?
Note that it seems to me that the solution proposed by #Jeroen is also good together with the default page transitions of jQuery Mobile, at least as I can see in this jsfiddle.
To be honest, the tip proposed by #Omar seems to me to have better integration with JQM, and I will try in the future to combine both answers, with a writeable computed observable to switch the JQM loader on/off.

Keep it simple! Show a loading overlay in your html by default, but use a visible: false binding of some kind. That way when the applyBindings call is done the UI will hide the overlay.
For example, suppose this view:
<div id="main">
<div id="loading-overlay" data-bind="visible: loading"></div>
Some content<br />
Some content
</div>
And suppose this view model:
vm = { loading: ko.observable(true) };
Then calling this:
ko.applyBindings(vm);
If for whatever reason it takes 7 secs to load, the loading-overlay will be shown until the UI is updated.
This approach is great if you have a client side DAL or some single point where you run Ajax calls, because you can follow this pattern:
vm.loading(true)
Ajax call with callbacks for success and failure
On callback do vm.loading(false)
Knockout will handle the overlay visibility for you.
See this fiddle for a demo, or check out this Stack Snippet:
vm = { loading: ko.observable(true) };
ko.applyBindings(vm);
// Mock long loading time:
window.setTimeout(function() {
vm.loading(false);
}, 5000);
html { height: 100%; }
body {
position: relative;
height: 100%;
width: 100%;
}
#loading-overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: url('http://img.cdn.tl/loading51.gif') white no-repeat center;
opacity: 0.75;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div id="main">
<div id="loading-overlay" data-bind="visible: loading"></div>
Some content<br />
Some content<br />
Some content<br />
Some content<br />
Some content<br />
<input type='text' value='cant edit me until overlay is gone' /><br />
<button>can't press me until overlay's gone!</button><br />
Some content<br />
Some content<br />
Some content
</div>

Related

Move one slider around another. JqueryUi

How to make one slider control another using jquery ui? I tried to follow this tutorial, but 'moveTo' action seems to be too old and doesn't work nowadays. I tested the function below and it doesn't seem to work, it keeps repeating one last function.
<div id="slider-1" class="slider-range" onclick="move()"></div>
<div id="slider-2" class="slider-range"></div>
function moveSlider2(e, ui) {
jQuery('#slider-2').slider('value', ui.value);
}
moveTo was deprecated indeed, but you can still use value method to do essentially the same thing: set a value for a slider programmatically. Note that if you work with sliders, you should work with sliders - and listen to the events raised by this library. For example:
const sliders = ['#slider-1', '#slider-2', '#slider-3'].map(
selector => $(selector).slider({
min: 1,
max: 5,
step: 0.1
})
);
sliders.forEach($el => {
// listening to `slide` event, fired when value is changed by a user
$el.on('slide', (_, {value}) => {
sliders.forEach($slider => $slider.slider('value', value));
});
});
.slider-range {
width: 50%;
margin: 5%;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/cupertino/jquery-ui.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="slider-1" class="slider-range"></div>
<div id="slider-2" class="slider-range"></div>
<div id="slider-3" class="slider-range"></div>

Jquery load popup from external file

I need to upload different text files each containing some popups.
I am using JQM 1.4.5 and I'm pretty sure I don't make any syntax errors.
My main program has a menu and the user can choose the text.
At this point, I have to upload the text file and the popup file related to that text.
All the attempts I've made using the '.load' function work for text but not for popups.
Can you give me some suggestions?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Popup Tooltip</title>
<link rel = "stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css">
<link rel = "stylesheet" href="style/style.css">
<script src = "https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src = "https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#t1").click (function(){
$("#corpus").load("text1/text1.html");
$("#pp").load("text1/popup1.html #popupBasic").enhanceWithin();
});
$("#t2").click (function(){
$("#corpus").load("text2/text2.html");
$("#pp").load("text2/popup2.html");
});
});
</script>
<style type="text/css">
a:link {color:red;
font-weight:bold;
text-decoration: none;
font-size:100%;
}
#tableMax{
border: 1px solid white;
margin:0 auto;
border-collapse:collapse;
}
#tableMax tr {border-bottom: 1px solid brown;
}
#tableMax td {padding: 18px 25px 18px 20px;
font-family: "Didot";
font-size: 20px;
background-color: antiquewhite;
color:black;
}
#tableMax td:nth-child(1) {
color:brown;
font-size:100%;
text-align:center;
}
</style>
</head>
<body>
<div data-role="page">
<div data-role="content">
<div id="menu" style="display:block;">
<button class="ui-btn ui-btn-b ui-btn-inline" id="t1">text 1</button>
<br>
<button class="ui-btn ui-btn-b ui-btn-inline" id="t2">text 2</button>
</div>
<div id="corpus"></div>
<div data-role="popup" id="pp"></div>
</div> <!-- chiude content -->
</div>
</body>
</html>
<!-- text1.html> -->
<table id="tableMax">
<tr><td>1a</td>
<td>This text contains a popup
</td></tr>
<tr><td>1b</td>
<td>This text also contains a popup
</td></tr>
</table>
<!-- popup1.html -->
<p id="popup_1" style="background:lightgreen; color:#000; max-width:500px;">
This is the content of popup 1a.</p>
<p id="popup_2" style="background:lightgreen; color:#000; max-width:500px;">
This is the content of popup 1b.</p>
Here are some suggestions to achieve what You want:
Basically, IMHO it is better not to create and destroy again and
again a JQM widget. If possible, create just at the beginning all
needed widgets and change the content, i.e. text and images
when You need it.
In my example I will show You both: dynamic destroying and instancing
a JQM table and dynamic changing the content of one existing popup.
Please, note that for a JQM table the thead and th tags are mandatory.
In Your example, You may need to show some data related to a table
row, but in my example I will attach the popup data to a single cell.
I believe, this is a more flexible approach.
The simplest way to create such a relation is to set a custom
data-attribute. You can call it whatever You want. Just for instance,
data-info: popup
After that, the popup content will be retrieved from the clicked
anchor, just before the popup will be open.
For the menu, instead of push-buttons I am using radio-buttons,
so the code will be much simpler, using just one event handler.
Moreover, it will be nice if You tell the user that something is
going on, by using a spinner and a visual feedback after the table
data has been downloaded (table fade-in).
Here is the most relevant code:
$(document)
.ready(function () {
$('input[name=files]').on('change', function (e) {
var path = e.target.id, $table = $("#tableMax").hide().table("destroy");
$.mobile.loading("show");
$.when($.get(path + '/popup.html'), $.get(path + '/text.html')).done(
function (popupData, tableData) {
$.mobile.loading("hide");
/* each data[0] will contain the response text */
$table.html(tableData[0]).table({create: function() {
var allPopups = $('<div></div>').append(popupData[0]);
$(this).fadeIn("slow").data("mobile-table").allHeaders.each(function() {
$(this).data("cells").each(function(){
$(this).find("a[href='#pp']").each(function () {
var popupLink = $(this).attr("data-info"),
popupContent = $(allPopups).find(popupLink);
$(this).data("popup-content", popupContent);
});
});
});
}
});
});
});
})
.on('pagebeforechange', function (e, ui) {
var link = ui.options.link, ctx = link && link.context, hash = ctx && ctx.hash;
if (hash == '#pp') $(hash).empty().html($(ctx).data('popup-content'));
});
Here is a full workng DEMO: https://plnkr.co/edit/3IXDqQJMVn2QYOed?open=lib%2Fscript.js

sticky left column in jquery mobile

Is it possible to accomplish the following in jquery mobile?
I've got a grid
<div class="ui-grid-a" >
<div class="ui-block-a" >
navigationtree
</div>
<div class="ui-block-b">
datatable with 50+ rows
</div>
</div>
when the table has too much data a scrollbar should appear and
block-b should be scrollable where block-a should be sticky at all times
so that the navigation stays in place.
is it possible to accomplish such a behaviour in jquery mobile?
Because 2 grid blocks share a width of 50% each its easy to achieve by setting block a to a fixed position and block b to float right.
Demo
http://jsfiddle.net/59v0gy6w/
<div class="ui-block-a" style="position:fixed">
<div class="ui-block-b" style="float:right">
cytasos has given a good answer! if you actually want just the ui-block-b to be scrollable, you can do it this way:
First scale the ui-content div to fill the device/screen height:
function ScaleContentToDevice() {
scroll(0, 0);
var content = $.mobile.getScreenHeight() - $(".ui-header").outerHeight() - $(".ui-footer").outerHeight() - $(".ui-content").outerHeight() + $(".ui-content").height();
$(".ui-content").height(content);
}
$(document).on("pagecontainershow", function () {
ScaleContentToDevice();
});
$(window).on("resize orientationchange", function () {
ScaleContentToDevice();
});
Next set the grid height to 100% and the block-b div to 100% height and overflow in CSS:
.ui-grid-a {
height: 100%;
}
.ui-block-b {
height: 100%;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
DEMO

Modal box "hidden" behind greyed out area

Im following along with http://multiplethreads.wordpress.com/tag/pagedown/
The example in the link above makes use of twitter bootstrap whereas i make use of zurb foundation.
Basically im trying to get a custom dialog box to insert images from my pagedown editior (sort of like how stackoverflow does it).
Im abale to pull up the modal box (foundation reveal) but it seems to be "behind" something and i cant seem to interact with it. Any ideas?
My code:
js file:
PH.ui.markdown = {
initialize: function () {
var markdownTextArea = $('textarea[data-markdown=true]');
if (markdownTextArea.length == 1) {
markdownTextArea.addClass('wmd-input')
.wrap("<div class='wmd-panel' />")
.before("<div id='wmd-button-bar'></div>")
.after("<div id='wmd-preview' class='wmd-preview'></div>");
var converter = Markdown.getSanitizingConverter();
var editor = new Markdown.Editor(converter);
editor.hooks.set("insertImageDialog", function (callback) {
//setTimeout(function () {
$('#myModal').foundation('reveal', 'open');
// }, 5000);
return true; // tell the editor that we'll take care of getting the image url
});
editor.run();
}
}
};
html:
<div id="myModal" class="reveal-modal">
<h2>Upload Image</h2>
<%= f.file_field :image %>
<button class="btn" id="insert_image_post">Insert Image</button>
<!-- <a class="close-reveal-modal">×</a> -->
</div>
I figured it out.
The wmd-prompt-background had a z-index of 1000:
<div class="wmd-prompt-background" style="position: absolute; top: 0px; z-index: 1000; opacity: 0.5; height: 1085px; left: 0px; width: 100%;"></div>
So i just added:
<style type="text/css">
#myModal {
z-index: 1500;
}
</style>
to my page and it worked.
One way to do it is to position the div of your modal directly under the <body>. This way you make sure that the modal is not part of elements with special z-index

How can I make a jQuery Mobile dialog that is not full screen?

I'd like to pop up a dialog that is not full screen, i.e., it "floats" above the page which opened it. Here is what I am trying:
<div data-role="page" id='Page1'>
<div data-role='button' id="Button1">Open Dialog</div>
</div>
<div data-role="dialog" id='Dialog'
style='width:200px; height:100px; top:100px; left:100px;'>
<div data-role='button' id="Button2">Close</div>
</div>
<script>
Button1.onclick = function() {
//$.mobile.changePage($('#Dialog'))
$.mobile.changePage('#Dialog',{role:'dialog'})
}
Button2.onclick = function() {
$(".ui-dialog").dialog("close");
}
Even though I set the bounds on Dialog's div, it is still full screen.
Here's what I came up with (after some great hints from Jasper):
<div data-role="page" id='Page1'>
<div data-role='button' id="Button1" >Open Dialog</div>
</div>
<div data-role="dialog" id='Dialog'>
<div data-role='header'id='Dialog_header'><h1>Dialog</h1></div>
<div data-role='button' id="Button2">Close</div>
</div>
<script>
Dialog_header.onclick= function(e){
$("#Dialog").fadeOut(500);
}
Button1.onclick = function(e) {
var $dialog=$("#Dialog");
if (!$dialog.hasClass('ui-dialog'))
{$dialog.page()};
$dialog.fadeIn(500);
}
Button2.onclick = function() {
$("#Dialog").fadeOut(500);
}
Button2 is a bonus: it shows how to close the dialog from code.
You can fiddle with it here:
http://jsfiddle.net/ghenne/Y5XVm/1/
You can force a width on the dialog like this:
.ui-mobile .ui-dialog {
background : none !important;
width : 75% !important;
}​
Notice I also removed the background so the dialog can appear on top of the other page. The only problem that remains is that when you navigate to the dialog, the other page is hidden so the dialog appears on top of a white background.
Here is a demo: http://jsfiddle.net/jasper/TTMLN/
This is a starting point for you, I think the best way to create your own popup is to manually show/hide the dialog so jQuery Mobile doesn't hide the old page.
Update
You can certainly use a dialog as a popup with a small amount of custom coding:
$(document).delegate('#dialog-link', 'click', function () {
var $dialog = $('#dialog');
if (!$dialog.hasClass('ui-dialog')) {
$dialog.page();
}
$dialog.fadeIn(500);
return false;
});​
Where dialog-link is the ID of the link that opens the dialog as a popup.
Here is a slight update to the CSS to center the modal horizontally:
.ui-mobile .ui-dialog {
background : none !important;
width : 75% !important;
left : 50% !important;
margin-left : -37.5% !important;
}​
And here is a demo: http://jsfiddle.net/jasper/TTMLN/1/
here is a plugin that u can use..this plugin is also customizable with ur own html.
simpleDialogue plugin for jquery mobile

Resources