Draggable not working with AJAX request - Angular - ajax

I would like to implement elements with a draggable property. You get what you wanted in part. I have several blocks that are built from the response of a web-service.
Use ng-repeat to represent the elements on the screen:
<div class = "declareContainer" ng-repeat = "item in group">
<!-- My Draggable Boxes -->
<div id="{{$index}}" title="{{$index}}" class="col-lg-6" style=" border radius: 15px; padding: 1%; ">
</div>
The loop is controlled by "group" object, however it is obtained by AJAX:
$Http.get (path + "getgroup"). Then (function (response) {
$ Scope.group = response.data;
}, Function (error) {
});
I use the following excerpt in my controller to apply a draggable property to the elements that are in the declareContainer div:
Angular.element (document) .ready (function () {
$ (".declareContainer"). Draggable ();
});
Elements are drawn normally, but lose a draggable property.
I ran tests and noticed that when defining the group object in static or exploit code (ng-repat already gets as object of the object during the construction of the app).
I tried to initialize "group" as null for the loop not toenter code here run while a response is not, but still giving the same problem.
Does anyone know of any way to solve this problem?

Related

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;

polymer iron-list only loading 20 items

I have an a test array that I am retrieving from iron-ajax with around 1000 items. I set that return array to the people property of my custom polymer element. Iron-list is displaying the first 20 results, but when i scroll down the rest of the results are not being loaded.
<link rel="import" href="/bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="/bower_components/iron-list/iron-list.html">
<link rel="import" href="/bower_components/iron-flex-layout/classes/iron-flex-layout.html">
<dom-module id="people-list">
<template>
<iron-list items="[[people]]" as="item" class="flex">
<template>
<div style="background-color:white; min-height:50px;">[[item.city]]</div>
</template>
</iron-list>
<iron-ajax
auto
id="ajaxPeopleList"
method="POST"
url="/people/list"
handle-as="json"
last-response="{{people}}">
</iron-ajax>
</template>
<script>
Polymer({
is: 'people-list',
properties: {
people: {
type: Array
}
}
});
</script>
</dom-module>
I think it may have to do with the height of the screen/iron-list element, but I am stuck and not sure how to proceed.
I can get it load all items if I set the height of the iron-list elements in pixels. But I just want it to fit on the screen. The docs make it look like you can use the iron-flex layout and use the class flex, which is what I tried to do in my sample code, but it has no effect.
This is because nothing is firing the iron-resize event to tell the iron-list to redraw the items. According to the docs:
Resizing
iron-list lays out the items when it recives a notification via the iron-resize event. This event is fired by any element that implements IronResizableBehavior.
By default, elements such as iron-pages, paper-tabs or paper-dialog will trigger this event automatically. If you hide the list manually (e.g. you use display: none) you might want to implement IronResizableBehavior or fire this event manually right after the list became visible again. e.g.
document.querySelector('iron-list').fire('iron-resize');
I've added the following to your code (which is probably a bit of a hack) and got it working:
ready: function () {
document.addEventListener("scroll", function () {
// fire iron-resize event to trigger redraw of iron-list
document.querySelector('iron-list').fire('iron-resize');
});
}
Ben Thomas is right. You're getting the json elements but it's not displayed because the iron-list needs to be redrawn. Since i had the same problem, i went to google polymers website and found THIS code example.
In short for your example:
<script>
// Only execute after DOM and imports (in our case the json file) has been loaded
HTMLImports.whenReady(function() {
Polymer({
is: 'people-list',
properties: {
people: {
type: Array
}
},
attached: function() {
// Use the top-level document element as scrolltarget
this.$.list.scrollTarget = this.ownerDocument.documentElement;
}
});
});

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);
}
});

Qtip2- tooltip with hidden element not shown

I´m using the http://qtip2.com/ tooltips. I want to use a hidden element, for that i´m using this code:
<script type="text/javascript">
// <![CDATA[
// Grab all elements with the class "hasTooltip"
$('.hasTooltip').each(function() { // Notice the .each() loop, discussed below
$(this).qtip({
content: {
text: $(this).next('div') // Use the "div" element next to this for the content
}
});
});
// ]]>
And under this code:
<div class="hasTooltip">Hover me to see a tooltip</div>
<div class="hidden">
<!-- This class should hide the element, change it if needed -->
<p><strong>Complex HTML</strong> for your tooltip <em>here</em>!</p>
</div>
If you hover over the "Hover me to see a tooltip", no tooltip is shown? No idea, why?
events: {
render: (event, api) ->
show: (event, api) ->
$('.qtip:visible').qtip('hide')
elements = $(api.get('content.text')).removeClass('hidden')
api.set('content.text', elements)
,
hide: (event, api) ->
}
I think its a bug in Qtip2, i had to manually remove the class

Approximating a mootools' .slide('out') on an element prior to Fx.Slide instantiation

It'd be simple to add var myFx = new Fx.Slide(element); to window.addEvent('domready'...), but because I am loading "sub-pages" using AJAX, the mootools objects of these elements inside these pages need to be instantiated after have loaded fully. If I tried using domready, the element would not be found, simple because it doesn't exist yet.
I've been working around this with setTimeout(function() { ... }, 500);, but this leaves a 500ms delay between page load and element effect creation.
i.e.
<div id="foo">TextTextText</div>
<script type="text/javascript">
setTimeout(function() {
var myFx = new Fx.Slide('foo').slideOut();
}, 500);
</script>
When the page is loaded, there is a clunky 500 ms before the element goes to its default state of... erm... "slided in". (slidded in?)
A workaround exists for .hide() and .show() effects, though, since I can simply write in the html <div id="foo" style="display: none;">
I've tried approximating the "slid in" state of an element with <div id="foo" style="height: 0px; overflow: hidden;">, but then the element stays hidden like that forever, and slide() doesn't do a damn thing on it.
I feel as though I am missing something simple.
Have you tried putting the Fx.Slide instantiation in the onComplete method of your XHR call ?
Example :
var myRequest = new Request({
method: 'get',
url: 'requestHandler.php',
onComplete : function() {
var myFx = new Fx.Slide(element);
// etc ...
}
});
I ended up resolving (to my satisfaction, anyway) the problem with a quick workaround.
<div id="foo" style="display: none;">TextTextText</div>
Click me!
<script type="text/javascript">
setTimeout(function() {
var myFx = new Fx.Slide('foo').slideOut();
$('toggler').addEvent('click', function() {
if ($('foo').getStyle('display') == 'none') $('foo').setStyle('display', 'block');
myFx.slideIn();
});
}, 500);
</script>
Element is hidden in initial state, and the slideOut() effect is run after the delay, but user won't notice since element is hidden. When called, element display is set to block (if not set already), and slideIn() is called.
Set initial state:
var myFx = new Fx.Slide('foo').hide();
Then later, when you want it to appear:
myFx.show().slideIn();

Resources