execute some function after rivets.js binding finishes - rivets.js

I'm kinda new to rivets and I don't fully understand it so I came upon which seems to be a pretty basic thing to do, but I couldn't do it.
I'm trying to execute some jQuery that only runs AFTER rivets finished binding everything? (it is a $().each that enables click event on each line created after rivets binds a list to a rv-each li element)
It isn't working, but if I try to manually call the function after the pages finished loading and after rivets finished binding (on the browser console), then everything works great.

You can wrap the code you want to execute after rivets binding is done inside a 0 timeout, so that it is pushed to the bottom of the callstack and will be executed after the existing tasks are completed.
var bigArr = [];
for (var i = 0; i < 20000; i++) {
/* ADJUST THIS untill you see the difference
WARNING: Keep it under control
*/
bigArr.push({
count: i
});
}
rivets.bind($("div"), { // bind rivets
arr: bigArr
});
setTimeout(function() {
console.log("rivets done it's thing!"); // executed when binding is done
}, 0);
console.log("Rivets..? Who!"); // executed before elements are rendered
div {
display: inline-block;
margin: 5px;
padding: 5px;
background: royalblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rivets/0.7.1/rivets.bundled.min.js"></script>
<div rv-each-item="arr">{item.count}</div>

Related

kendo ui - override k-animation-container style for one dropdown only

I use kendo-ui dropdown.
I add some ovveriding-css, and it works well.
.k-animation-container {
//this is popup that is html is rendered out of the page element
//so it cannot be selected by id / panaya class / panaya element
.k-popup.k-list-container {
.k-item,
.k-item.k-state-selected,
.k-item.k-state-focused {
background-color: transparent;
color: $darken-gray-color;
margin-left: 0;
margin-top: 0;
}
}
}
The problem is, that while each dropdown has other input element instance, the list has one instance that is hidden and when you click any combo - is shown near the currently clicked combo.
What say - when you ovveride the list-container style - dows it for all of the combooxes.
Is there any solution for this issue?
Well this is a known problem, for every popup kendo renders independent div with class k-animation-container
You can try with this solution suggested on telerik forum:
k-animation-container
$("#spreadsheet").on("click", ".k-spreadsheet-editor-button", function(e) {
var animationContainer = $(".k-animation-container").last();
// use some custom conditional statement that will determine if this is the correct list popup, e.g. check what's inside the popup
if (true) {
animationContainer.children(".k-popup").css("min-width", 200);
}
});
Didn't try it my self, gl.
One solution I found was to use
popup: {
appendTo: $(some parent with ID)
}
This way we can manipulate styling of that particular .k-animation-container.
But this doesn't work on every widget, unfortunately.
My team find a great solution:
There is an option to give the input-element custom id.
Then you can select the list-container by the custom id you gave +'list' str.
Now, if you want to get the k-animation-container, you can select the list element and then request its parent.
Code sample:
The input element:
<span
kendo-multi-select
id="my-type-dd"
k-options="$ctrl.getVMultySelectConfig()"
k-ng-model="$ctrl.selectedTypes"
></span>
Selectors:
If you need only the k-list-container and not must the k-animation-container, you can do that by css:
.k-animation-container #my-type-dd-list {
//this is popup that is html is rendered out of the page element
//the id is the id you give to the element + '-list'
&.k-popup.k-list-container {
padding: $space-normal 0 $space-small $space-small;
box-shadow: 3px 3px 1px rgba(0, 0, 0, 0.1);
}
}
If you need the k-aniamation-container you need to select it by jQuery becouse css doesn't have parent selector:
var kAnimationElement = $("#my-type-dd-list").parent();

Dojo class event listener disappears upon subsequent instantiation

I have a simple class called Draggable, which has a Moveable and a click event listener:
define([
'dojo/dom',
'dojo/query',
'dojo/dom-style',
'dojo/dnd/Moveable',
'dojo/_base/declare'
], function(
dom,
query,
domStyle,
Moveable,
declare
){
return declare(null, {
constructor: function(id){
this.id = id;
dom.byId('draggables').innerHTML +=
'<div id="' + id + '" style="width: 100px; height: 100px; border: 1px solid #000;"></div>';
this.moveable = new Moveable(id, {
handle: dom.byId(id)
});
query('#' + id).on('click', function(){ console.log(id); });
}
});
});
In the main HTML file, index.html, I simply create two instances of Draggable, A and B:
<script>
require([
'dojo',
'dojo/query',
'extras/Draggable'
], function(
query,
Draggable
){
var a = new Draggable('A');
var b = new Draggable('B');
});
</script>
If I created Draggable A alone (without creating Draggable B), I can drag Draggable A around, and whenever I click on it, the console will log "A" as expected.
However, once I create Draggables A and B (as shown in the code), only Draggable B can be dragged around, and only when I click on Draggable B will the console log "B". It seems as though the moment Draggable B is created, Draggable A loses both its Moveable and its event listener!
Well, you'd better go another way. Movable class designed so you can't use it as mixin in your widget. It's constructor requires a node as parameter and templated widget don't have node at this moment, except srcNodeRef, if it was passed.
So, I'd suggest you do the following:
1 Create templated widget without Movable class. Attach your event listeners, if you need. It will work out of the box without any collisions if you properly use data-dojo-attach-event attribute or any other way you like.
Code of widget may look like:
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin"
], function (
declare,
_WidgetBase,
_TemplatedMixin
) {
"use strict";
return declare("Draggable", [_WidgetBase, _TemplatedMixin], {
templateString: "<div data-dojo-attach-event='click: clickHandler' style='width: 100px; height: 100px; border: 1px solid #000'>draggable div</div>",
clickHandler: function (e) {
console.log("Clicked:", this.id, e);
}
});
});
2 Somewhere in your page you'll create your widgets and make them movable like:
<script>
require(["dojo/dnd/Moveable", "Draggable"], function (Movable, Draggable){
let d1 = new Draggable();
d1.placeAt("myContainer");
let d2 = new Draggable();
d2.placeAt("myContainer");
let m1 = new Movable(d1.domNode);
let m2 = new Movable(d2.domNode);
});
</script>
<div id="myContainer"></div>
I've tested, it worked for me. Hope it'll help;

In firefox, the code in iframe of my website can't be loaded properly, but success to be loaded if the iframe is unhidden and reload the iframe again

Hope my Question is enough clear. I own a website.
http://khchan.byethost18.com
My problem is in the tab "Calendar", it run properly in chrome, ie. but not in fixfox.
my design is that when I hover the calendar tab. the page of calendar will show.
but in firefox, when I do that, it don't show properly. developer tool show $bookblock.bookblock is not a function. If I reload the frame, such error message will not show.
If I directly load "http://khchan.byethost18.com/cal.php
It can show properly and such error message don't appear.
so I guess may be something is not load properly. I already try add $(top.document,document).ready({function(){}); or replace the jquery library to the head or body. the problem still exist.
since the coding is very long. I only write the iframe tag.Please try to use developer tool to view my code.
I tried document.getElementById('CalF').contentWindow.location.reload();
if I already hover the calendar tab, the tab can be reload properly.
but if not, the developer tool display the same error message.
so, I think the major key to the problem is that the jquery tab affect something so that the tab "CalF" can't work properly.
.boxoff{
display: none;
}
<article class='boxoff'> //this article will be hidden until I delete the class.
<iframe id=CalF src="cal.php" style="top: 0;"></iframe>
</article>
Thanks.
iframeLoaded()
Update 2
OP explained that the iframe must be invisible initially. While this may seem an impossibility since iframes do not load when it or one of it's ancestor elements are display: none;. The key word is invisible which is a state in which the iframe is not visible.... There are three CSS properties that come to mind and one of them is actually shouldn't be used in this situation.
display: none; This is the property being used by OP and this property actually hinders the iframe's loading. The reason why is when in that state of invisibility, the iframe is not in the DOM according to Firefox's behavior.
opacity: 0; This property renders the iframe invisible as well and Firefox seems to recognize the invisible iframe just fine.
visibility: hidden; This seems to be an acceptable as well....
So try this code that I use to suppress the FOUC:
Child Page
function init(sec) {
var ms = parseFloat(sec * 1000);
setTimeout('initFadeIn()', ms);
}
function initFadeIn() {
$("body").css("visibility","visible");
$("body").fadeIn(500);
}
HTML
<body style="visibility: hidden;" onload="init(2);">
Update 1
I made an alternative solution because I hate leaving a demo that doesn't completely work★.
Ok this relies on cal.php window.onload event which is basically the slowest but the most stablest phase of loading there is.
Initially, #overlay will block any user interaction while calF is loading.
Once calF is completely loaded, it will call iframeLoaded function that's located on the parent page.
iframeLoaded will remove #overlay (I added a setTimeout for good measure but it's probably not necessary.)
I'm not that familiar with PHP syntax, so you'll have to modify the following code✶ and place it in cal.php
window.onload = function() {
parent.iframeLoaded();
}
Then on the parent page:
function iframeLoaded() {
setTimeout(function() {
$('#overlay').hide(750);
}, 1500);
}
The code above as well as the required HTML and CSS is in the snippet below.
★ Note: The code in the snippet should work, but this snippet won't of course because there's some code that needs to be on the child page. That's just a shoutout to all the downvoters out there ;-)
Snippet 1
// iframeLoaded will remove the overlay when cal.php has completely loaded
function iframeLoaded() {
setTimeout(function() {
$('#overlay').hide(750);
}, 1500); //<========[1 to 2 (1000 - 2000ms) seconds should give you plenty of time]
}
/*~~~~~~~~~~~~~~~~~~~~~~~~[Code in cal.php]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// When everything (DOM, script, images. etc...) is loaded on cal.php, call iframeLoaded function that is on the parent's page.
window.onload = function() {
parent.iframeLoaded();
}
#overlay {
background: rgba(0, 0, 0, .3);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
#CalF {
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="overlay"></div>
<iframe id="CalF" src="http://khchan.byethost18.com/cal.php" height="100%" width="100%" frameborder="0" style="top: 0;"></iframe>
✶ Function loadedIframe() inspired by SO5788723
Snippet 2
document.getElementById('CalF').onload = function(e) {
var over = document.getElementById('overlay');
over.classList.add('hide');
}
#overlay {
background: rgba(0, 0, 0, .3);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.hide {
display: none;
}
#CalF {
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="overlay"></div>
<iframe id="CalF" src="http://khchan.byethost18.com/cal.php" height="100%" width="100%" frameborder="0" style="top: 0;"></iframe>
$(document).ready seems to be called too soon, based on parent page instead of iframe content.
here you have solution to a similar problem:
jQuery .ready in a dynamically inserted iframe

With knockout foreach binding to TBODY, how to show loading animation during and AFTER ajax call

User makes repeated queries against database over the course of the day; each time, the results are cleared from the table and new data are injected into the table:
<tbody data-bind="foreach: MyVM.Results">
and in code before the ajax call:
MyVM.Results.removeAll();
I want to display an animated spinner of some kind while the ajax call is underway (Edit: and then also when ko is still working on creating the table rows after the ajax call returns).
EDIT: What is "the knockout way" of displaying this animation when there's a standard ajax call with fail and success callbacks, and the tbody is foreach-bound to the observableArray Results?
EDIT2: configuring the Ajax call itself in jQuery with beforeSend and complete callbacks does not solve the problem entirely because taking UI action when the ajax call itself is complete does not account for the delay of knockout's for-each binding of the data to the table. is there a knockout event that signals "binding complete"?
EDIT3: The answers are not understanding the problem. My fault for trying to make it simple and leaving out a lot of code. This has nothing to do with Ajax. Consider this very simple scenario, which is exaggerated to make the problem clearer. Let's say you have an array with a million items in it. Ajax call is already completed! Now you want to get the items in that array into a ko observableArray to which your TABLE TBODY is bound with for-each binding. This binding process itself is going to take some seconds to complete We want to hide our animation after the binding has finished and something is displaying on the HTML page. Is there a way to know that the table rows created by knockout have begun to be rendered in the UI?
I developed a custom loading animation for doing this.
<!--Preloader-->
<div id="preloader">
<div class="preloader" data-bind="visible: _isShow">
<div class="loader-content">
<img src="img/ajax-loader.gif" alt="Loading.." style="margin: 0px auto 20px auto;">
<br>
<span class="loader-txt">Loading... Please wait....</span>
</div>
<!--End of loader-content-->
</div>
<!--End of preloader-->
</div>
CSS codes
/*****************Preloader******************/
.preloader {
background: rgba(0, 0, 0, 0.9);
width: 100%;
position: fixed;
z-index: 10000;
top:0;
bottom:0;
left:0;
right:0;
}
.preloader-hidden{
visibility: hidden;
}
.preloader .loader-content {
text-align: center;
top: 50%;
margin-top: -22px;
position: absolute;
left: 50%;
margin-left: -75px;
}
.loader-txt {
font-size: 14px;
color: #fff;
vertical-align: middle;
margin-left: 15px;
}
Javascript Code for preloader viewmodel
function PreloaderViewModel() {
var self = this;
self._isShow = ko.observable(false);
self.ShowPreloader = function() {
self._isShow(true);
};
self.HidePreloader = function() {
self._isShow(false);
};
}
Register the view model as bellow
var preloaderVM;
if ($.isEmptyObject(preloaderVM)) {
preloaderVM = new PreloaderViewModel();
ko.applyBindings(preloaderVM, document.getElementById("preloader"));
preloaderVM.HidePreloader();
}
Use it in ajax call like bellow.
//Show preloader
preloaderVM.ShowPreloader();
$.ajax({
type: "GET",
dataType: "json",
url: yourServiceUrl,
data: searchdata,
success: function (data) {
//do whatever in data return from ajax call
//Hide preloader
preloaderVM.HidePreloader();
},
error: function (error) {
console.log(error.responseText);
preloaderVM.HidePreloader();
}
});
If you want to change the text showing in pre-loader by defining a property on preloaderviewModel.
ko way is to use model to drive the view.
If the standard ko bindings are not enough (for instance, if gif animation is not enough for you), create a customised ko.bindingHandlers.
An idea ko app hides all DOM manipulation inside ko.bindingHandlers.
Here is a template that I use for ajax data loading.
HTML
<!-- ko if: loading -->
<!-- show spinner -->
<!-- /ko -->
<!-- ko ifnot: loading -->
<!-- show result, your data-bind="foreach: Results" -->
<!-- /ko -->
Javascript
//assume you use self to hold 'this' pointer in viewModel constructor
self.loading = ko.observable(false);
// in your data loading action
self.loadRemoteData = function() {
//start loading
self.loading(true);
$.ajax({
// ...
success: function(data) {
// update Results(data);
},
fail: function() { ...},
complete: function() {
//finish loading
self.loading(false);
}
});
};
I found the answer. Instead of looping through the Ajax data and adding an object to the ko observableArray on each iteration, I have to pop or shift() each item off the Ajax data array and push it onto the observableArray in a custom event using trigger(). The eventhandler invokes the custom event again and again while data contains items. Thus, the UI is not blocked but table rows begin to appear immediately.
In my case, the web app is running on an intranet, and the local database can return 10,000 rows on the LAN in the blink of an eye, but it takes a good number of seconds for all 10,000 rows to be created in the HTML Table using knockout for-each binding. With the event approach, the rows start becoming visible to the user instantly.
$(document).on("PushIt", function (event, data, results) {
var item = data.shift();
var Cust = new Customer(
item["firstname"],
item["lastname"],
item["addr1"],
item["city"],
item["state"],
item["zipcode"]
)
results.push(Cust);
if (data.length > 0) {
// timeout avoids recursion-limit problems
setTimeout(function () { $(document).trigger("PushIt", [data, results]); }, 1);
}
});

AngularJS : router : load view manually from within controller

Is there a way of manually loading the view from within the controller, after say some animation was triggered first? The scenario I have is the previous page content sliding up, after that the view would be updated when being off-the screen and once ready - slides back down with the new view from the new controller.
I've got already the router set up, but it just instantly replaces the view whenever the new controller is called.
Any fiddle if possible please?
Code in Controller shouldn't manipulate DOM, directives should. Here is directive to prevent preloading content of element with "src" (by browser's parser) and show content of element only after loading, and before loading show splash with spinner:
directive('onloadSrc', function($compile) {
return function(scope, element, attrs) {
element.bind('load', function() {
var parent = $compile(element[0].parentElement)(scope);
if (!element.attr('src') && attrs.onloadSrc) {
element.attr("src", attrs.onloadSrc);
// replace this dirty hardcode with your template for splash spinner
var spinner_div = $compile('<div style="z-index: 100; width: '+element.attr('width')+'px; height: '+element.attr('height')+'px; display:block; vertical-align:middle;"><img src="/img/spinner.gif" style="position: absolute; left: 50%; top: 50%; margin: -8px 0 0 -8px;"/></div>')(scope);
attrs.onloadSrc = "";
parent.prepend(spinner_div);
element.css("display", 'none');
attrs.xloading = spinner_div;
}
else {
if (attrs.xloading) {
attrs.xloading.remove();
attrs.xloading = false;
element.css("display", 'block');
}
}
}
);
}});
To use this directive, leave empty attribute src of element and fill attribute onload-src.
Angular has animations build in in unstable branch, which should perfectly fit your scenario.
Just check out http://www.nganimate.org/angularjs/tutorial/how-to-make-animations-with-angularjs.
ng-view directive has build in 'enter' and 'leave' animations.
Check you this sample: http://jsfiddle.net/nFhX8/18/ which does more less what you'd like to achieve.

Resources