Infinite scroll is not triggered framework7 - infinite-scroll

I am using framework7.In AJAX success function I am loading first 20 people and remaining to be loaded by infinite scroll.
This is the div element
<div class="page-content infinite-scroll" data-distance="50">
<div class="searchbar-backdrop"></div>
<div class="entry_content">
<div class="members_list list searchbar-found list-block">
<ul class="row22">
</ul>
</div>
<div class="block searchbar-not-found">
<div class="block-inner">Nothing found</div>
</div>
</div>
Also this is the script
$on('pageInit', () => {
app.request({
url: base_url+api_path+'/members_directory.php',
method: "POST",
timeout: 0,
dataType: "json",
beforeSend: function () {
app.preloader.show();
},
success: function(data) {
app.preloader.hide();
console.log(data);
for(var i=0;i<20;++i){
// for(var i=0;i<data.getEmployees.length;++i){
var user_id = data.getEmployees[i].user_id;
var username = data.getEmployees[i].username;
var profile_photo = data.getEmployees[i].profile_photo;
var employee_name = data.getEmployees[i].employee_name;
var employee_id = data.getEmployees[i].employee_id;
$('.page_members_dir .members_list ul').append(
'<li class="item-content member_item"><div class="item-title member_name">'+employee_name+'</div></li>'
);
};
/*infinite*/
var loading = false;
// Last loaded index
var lastIndex = $('.list-block li').length;
// Max items to load
var maxItems = 60;
// Append items per load
var itemsPerLoad = 20;
// Attach 'infinite' event handler
$('.infinite-scroll').on('infinite', function () {
// app.attachInfiniteScroll($('.infinite-scroll'));
console.log("inside");
// Exit, if loading in progress
if (loading) return;
// Set loading flag
loading = true;
// Emulate 1s loading
setTimeout(function () {
// Reset loading flag
loading = false;
if (lastIndex >= maxItems) {
// Nothing more to load, detach infinite scroll events to prevent unnecessary loadings
app.detachInfiniteScroll($('.infinite-scroll'));
// Remove preloader
$('.infinite-scroll-preloader').remove();
return;
}
// Generate new items HTML
var html = '';
for (var i = lastIndex + 1; i <= data.getEmployees.length; i++) {
var user_id = data.getEmployees[i].user_id;
var username = data.getEmployees[i].username;
var profile_photo = data.getEmployees[i].profile_photo;
var employee_name = data.getEmployees[i].employee_name;
var employee_id = data.getEmployees[i].employee_id;
html += '<li class="item-content member_item"><div class="item-title member_name">'+employee_name+'</div></li>';
}
console.log(html);
// Append new items
$('.list-block ul').append(html);
// Update last loaded index
lastIndex = $('.list-block li').length;
}, 1000);
});
},
error: function(data) {
//console.log('error');
console.log(data);
}
});
});//pageInit
return $render;
}
I am not getting any errors in console.
The list data is getting from ajax page.
If I console after $('.infinite-scroll').on('infinite', function () nothing is displayed.
Is this right way to infinite scroll use in AJAX success function.
Please help

Related

Google Markers with dynamic data for Ionic Modal

I am new to hybrid mobile app creation. And my use case is very simple. I have a single ionic modal using template html.
What I want is populating the same ionic template with different values based on some records data. Basically it is a google map and on click on any of the markers, the same template should open with different values based on the marker.
My controller code -
.controller('MyLocationCtrl', function(
$scope,
$stateParams,
force,
$cordovaGeolocation,
$ionicModal,
GoogleMapService,
ForceService,
$q
) {
console.log('this is in my location page');
var currentPosition = GoogleMapService.getCurrentLocation();
var restaurantModal = $ionicModal.fromTemplateUrl('templates/bottom-sheet.html', {
scope: $scope,
viewType: 'bottom-sheet',
animation: 'slide-in-up'
});
var allContacts = ForceService.getAllContactsWithGeo();
var promises = [];
promises.push(currentPosition);
promises.push(allContacts);
promises.push(restaurantModal);
var allMarkers = [];
var allContactDetails = [];
currentPosition.then(
function(position) {
console.log('position data -->', position);
var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
$scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
var bounds = new google.maps.LatLngBounds();
allContacts.then(
function(contacts) {
console.log('contacts final -->', contacts);
for (var i=0; i<contacts.records.length; i++) {
var contact = contacts.records[i];
console.log('single contact -->', contact.MailingLatitude, contact.MailingLongitude);
var contactlatLng = new google.maps.LatLng(contact.MailingLatitude, contact.MailingLongitude);
var contactInfo = {};
//contactInfo.marker = {};
var marker = new google.maps.Marker({
map: $scope.map,
animation: google.maps.Animation.DROP,
position: contactlatLng
});
contactInfo.marker = marker;
contactInfo.recordDetails = contact;
allMarkers.push(marker);
allContactDetails.push(contactInfo);
// Set boundary for markers in map
bounds.extend(contactlatLng);
}
// Fit map based on markers
$scope.map.fitBounds(bounds);
}
);
// google.maps.event.addListenerOnce($scope.map, 'idle', function(){
// });
},
function(error) {
console.log("Could not get location" + error);
}
);
// Add listener for marker pop up once all promises resolved
$q.all(promises).then(
function(values) {
console.log('first -->', values[0]);
console.log('second -->', values[1]);
console.log('third -->', values[2]);
var detailModal = values[2];
$scope.modal = detailModal;
for (var i=0; i<allContactDetails.length; i++) {
allContactDetails[i].marker.addListener('click', function() {
console.log('helllos from marker');
console.log('all contactInfo -->', allContactDetails[i].recordDetails.Name);
$scope.contactName = allContactDetails[i].recordDetails.Name;
detailModal.show();
});
}
}
);
})
Front end template code -
<script id="templates/bottom-sheet.html" type="text/ng-template">
<ion-bottom-sheet-view>
<ion-header-bar align-title="left">
<h1 class="title">New Particle</h1>
<button class="button button-icon icon ion-android-close" ng-click="modal.hide()"></button>
{{contactName}}
</ion-header-bar>
</ion-bottom-sheet-view>
</script>
Now the modal opens properly when i click on the google marker, but I am not sure how to pass dynamic data to the pop modal.
Since you are doing this :
var restaurantModal = $ionicModal.fromTemplateUrl('templates/bottom-sheet.html', {
scope: $scope,
viewType: 'bottom-sheet',
animation: 'slide-in-up'
});
Your modal can access to the scope of your controller.
So if you declare any variable in your controller it will be accessible through the modal.

Ionic There is a Bug? ion-refresher and ion-infinite-scroll

I found an compatibility issue using the two mentioned components on same list, my html and js code below:
HTML:
<ion-content ng-controller="homeCtrl">
<ion-refresher on-refresh="loadNewContent()" pulling-text="LoadMore..." spinner="android"></ion-refresher>
<div ng-repeat="item in items">
<img ng-src="{{pathUrl+item['path']}}" style="height: auto;width:100%;">
</div>
<ion-infinite-scroll ng-if="hasMore" on-infinite="loadMoreContent()" spinner="spiral" distance="5" immediate-check="false"></ion-infinite-scroll>
</ion-content>
JavaScript:
JiCtrls.controller('homeCtrl', ['$scope', '$timeout', 'DbService', 'JsonService',
function ($scope, $timeout, DbService, JsonService) {
$scope.items = [];
$scope.hasMore = true;
var run = false;
loadData(0);
//下拉更新
$scope.loadNewContent = function () {
loadData(2);
// Stop the ion-refresher from spinning
$scope.$broadcast("scroll.refreshComplete");
};
//上拉更新
$scope.loadMoreContent = function () {
loadData(1);
$scope.$broadcast('scroll.infiniteScrollComplete');
};
function loadData(stateType) {
if (!run) {
run = true;
if ($scope.sql == undefined) {
$scope.sql = "select top 5 * from information ";
}
DbService.getData($scope.sql, '').success(function (data, status, headers, config) {
var convertData = JsonService.convertData(data);
if (stateType == 1 || stateType == 0) {
// $scope.items = $scope.items.concat(convertData);
for (var i = 0; i < convertData.length; i++) {
$scope.items.push(convertData[i]);
}
}
else {
for (var i = 0; i < convertData.length; i++) {
$scope.items.unshift(convertData[i]);
}
}
if (convertData == null || convertData.length <= 0) {
$scope.hasmore = false;
;
}
$timeout(function () {
run = false;
}, 500);
}).error(function (errorData, errorStatus, errorHeaders, errorConfig) {
console.log(errorData);
});
}
}
}
]);
Everything is normal in Chrome browser and Iphone, but in a part of the Android phone there is a big problem.When ion-refresher trigger on-refresh function,the on-infinite="loadMoreContent()" function will run indefinitely. So,What is the problem?
Try to put $scope.$broadcast("scroll.refreshComplete"); and $scope.$broadcast('scroll.infiniteScrollComplete'); into DbService.getData(...).success() callback, not in functions triggered by on-infinite and on-refresh.
Explanation:
When the user scrolls to the end of the screen, $scope.loadMoreContent which is registered with on-infinite is triggered. The spinner shows, and ion-infinite-scroll pauses checking whether the user has reached the end of the screen, until $scope.$broadcast('scroll.infiniteScrollComplete'); is broadcast, when it hides the spinner and resumes the checking.
In your code, imagine there's a 3s delay in network, no new item is added to the list in that 3s. As a result, the inner height of ion-content is never updated, so the check that determines whether the user has reached the end of the screen will always return true. And you effectively prevent ion-infinite-scroll from pausing this checking by broadcasting scroll.infiniteScrollComplete the moment on-infinite is triggered. That's why it will update indefinitely.
To improve your code quality and prevent future problems, you may need to call $scope.$apply in your DbService.getData().success() callback (depending on the implementation of getData) and manually notify ion-content to resize in the callback.
P.S. 来自中国的Ionic开发者你好 :-) 两个中国人讲英语真累啊
Update
I've made a codepen that combines both ion-refresher and ion-infinite-scroll, I think it's working pretty fine.
http://codepen.io/KevinWang15/pen/xVQLPP
HTML
<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>ion-refresher + ion-infinite-scroll 2</title>
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
</head>
<body ng-controller="MyCtrl">
<ion-header-bar class="bar-positive">
<h1 class="title">ion-refresher + ion-infinite-scroll 2</h1>
</ion-header-bar>
<ion-content delegate-handle="mainScroll">
<ion-refresher on-refresh="doRefresh()">
</ion-refresher>
<ion-list>
<ion-item ng-repeat="item in list">{{item}}</ion-item>
</ion-list>
<ion-infinite-scroll
ng-if="hasMore"
on-infinite="loadMore()"
distance="1%">
</ion-infinite-scroll>
</ion-content>
</body>
</html>
JS
angular.module('ionicApp', ['ionic'])
.controller('MyCtrl', function($scope, $timeout, $q, $ionicScrollDelegate) {
/*
list of items, used by ng-repeat
*/
$scope.list = [];
var itemOffset = 0,
itemsPerPage = 5;
/*
used by ng-if on ion-infinite-scroll
*/
$scope.hasMore = true;
/*
isRefreshing flag.
When set to true, on data arrive
it first empties the list
then appends new data to the list.
*/
var isRefreshing = false;
/*
introduce a custom dataFetcher instance
so that the old fetch process can be aborted
when the user refreshes the page.
*/
var dataFetcher=null;
/*
returns a "dataFetcher" object
with a promise and an abort() method
when abort() is called, the promise will be rejected.
*/
function fetchData(itemOffset, itemsPerPage) {
var list = [];
//isAborted flag
var isAborted = false;
var deferred = $q.defer();
//simulate async response
$timeout(function() {
if (!isAborted) {
//if not aborted
//assume there are 22 items in all
for (var i = itemOffset; i < itemOffset + itemsPerPage && i < 22; i++) {
list.push("Item " + (i + 1) + "/22");
}
deferred.resolve(list);
} else {
//when aborted, reject, and don't append the out-dated new data to the list
deferred.reject();
}
}, 1000);
return {
promise: deferred.promise,
abort: function() {
//set isAborted flag to true so that the promise will be rejected, and no out-dated data will be appended to the list
isAborted = true;
}
};
}
$scope.doRefresh = function() {
//resets the flags and counters.
$scope.hasMore = true;
itemOffset = 0;
isRefreshing = true;
//aborts previous data fetcher
if(!!dataFetcher) dataFetcher.abort();
//triggers loadMore()
$scope.loadMore();
}
$scope.loadMore = function() {
//aborts previous data fetcher
if(!!dataFetcher) dataFetcher.abort();
//fetch new data
dataFetcher=fetchData(itemOffset, itemsPerPage);
dataFetcher.promise.then(function(list) {
if (isRefreshing) {
//clear isRefreshing flag
isRefreshing = false;
//empty the list (delete old data) before appending new data to the end of the list.
$scope.list.splice(0);
//hide the spin
$scope.$broadcast('scroll.refreshComplete');
}
//Check whether it has reached the end
if (list.length < itemsPerPage) $scope.hasMore = false;
//append new data to the list
$scope.list = $scope.list.concat(list);
//hides the spin
$scope.$broadcast('scroll.infiniteScrollComplete');
//notify ion-content to resize after inner height has changed.
//so that it will trigger infinite scroll again if needed.
$timeout(function(){
$ionicScrollDelegate.$getByHandle('mainScroll').resize();
});
});
//update itemOffset
itemOffset += itemsPerPage;
};
});
The correct Javscript is as follows:
JiCtrls.controller('homeCtrl', ['$scope', '$timeout', '$ionicScrollDelegate', 'DbService', 'JsonService',
function ($scope, $timeout, $ionicScrollDelegate, DbService, JsonService) {
$scope.items = [];
$scope.hasMore = true;
loadData(0);
//下拉更新
$scope.loadNewContent = function () {
loadData(2);
};
//上拉更新
$scope.loadMoreContent = function () {
loadData(1);
};
function loadData(stateType) {
if ($scope.sql == undefined) {
$scope.sql = "select top 5 * from information”;
}
DbService.getData($scope.sql, '').success(function (data, status, headers, config) {
var convertData = JsonService.convertData(data);
if (stateType == 0) {
for (var i = 0; i < convertData.length; i++) {
$scope.items.push(convertData[i]);
}
}
else if (stateType == 1) {
// $scope.items = $scope.items.concat(convertData);
for (var i = 0; i < convertData.length; i++) {
$scope.items.push(convertData[i]);
}
$timeout(function () {
$scope.$broadcast('scroll.infiniteScrollComplete');
}, 500);
}
else {
for (var i = 0; i < convertData.length; i++) {
$scope.items.unshift(convertData[i]);
}
// Stop the ion-refresher from spinning
$timeout(function () {
$scope.$broadcast("scroll.refreshComplete");
}, 500);
}
$ionicScrollDelegate.resize();
if (convertData == null || convertData.length <= 0) {
$scope.hasmore = false;
}
}).error(function (errorData, errorStatus, errorHeaders, errorConfig) {
console.log(errorData);
});
}
}
]);

Vimeo drop uploader to click uploader

im using vimeo drop uploader on my site. i got the uploder from
https://github.com/websemantics/vimeo-upload
its working well when i drop the image. but i dont know how to on click to open uploder window..
the uploder dont have the file input its only have the div
this is html
<div class="progress">
<div id="progress" class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="46" aria-valuemin="0" aria-valuemax="100" style="width: 0%">0%
</div>
</div>
<div id="drop_zone">Drop files here</div>
and they use this script
<script>
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object.
var accessToken = document.getElementById("accessToken").value;
var upgrade_to_1080 = document.getElementById("upgrade_to_1080").checked;
// Set Video Data
var videoName = document.getElementById("videoName").value;
var videoDescription = document.getElementById("videoDescription").value;
// Clear the results div
var node = document.getElementById('results');
while (node.hasChildNodes()) node.removeChild(node.firstChild);
// Rest the progress bar
updateProgress(0);
var uploader = new MediaUploader({
file: files[0],
token: accessToken,
upgrade_to_1080: upgrade_to_1080,
videoData: {
name: (videoName > '') ? videoName : 'Default name',
description: (videoDescription > '') ? videoDescription : 'Default description'
},
onError: function(data) {
var errorResponse = JSON.parse(data);
message = errorResponse.error;
var element = document.createElement("div");
element.setAttribute('class', "alert alert-danger");
element.appendChild(document.createTextNode(message));
document.getElementById('results1').appendChild(element);
},
onProgress: function(data) {
updateProgress(data.loaded / data.total);
},
onComplete: function(videoId) {
var url = "https://vimeo.com/"+videoId;
document.getElementById("video").value = url;
//var a = document.createElement('a');
// a.appendChild(document.createTextNode(url));
// a.setAttribute('href',url);
//
// var element = document.createElement("div");
// element.setAttribute('class', "alert alert-success");
// element.appendChild(a);
//
// document.getElementById('results').appendChild(element);
}
});
uploader.upload();
}
/**
* Dragover handler to set the drop effect.
*/
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
/**
* Wire up drag & drop listeners once page loads
*/
document.addEventListener('DOMContentLoaded', function () {
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
});
var elem = document.getElementById('drop_zone');
if(elem && document.createEvent) {
var evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, false);
elem.dispatchEvent(evt);
}
/**
* Updat progress bar.
*/
function updateProgress(progress) {
progress = Math.floor(progress * 100);
var element = document.getElementById('progress');
element.setAttribute('style', 'width:'+progress+'%');
element.innerHTML = progress+'%';
}
progress
</script>
Can you help me on this how to i upload an video on click..
Demo https://github.com/googledrive/cors-upload-sample
Thanks

Load Jquery Accordion after button click using Jquery

I am using JQuery UI Accordion, it works fine with the static content. However when i am loading the H3 and Div tags of the accordion from the ajax rest service call. The data is coming up properly but accordion is not loading up
onSuccess: function (data) {
var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
var html = "";
for (var i = 0; i < results.length; i++) {
html += "<div><h3><a href=\"#\">";
html += results[i].Cells.results[3].Value;
html += "</a></h3><p>"
html += results[i].Cells.results[6].Value;
html += "</p></div>";
}
$("#results_accordion").accordion();
My Accordion Div is empty initially whihc i want to fill up with the data from the above service call on button click.
$("#results_accordion").accordion();
Any help ?
$("#results_accordion").html(html).accordion();
you should first add the html content to your page before you execute the accordion function
This is my actual click event which is called..
function onclic(queryTerms) {
Results = {
element: '',
url: '',
init: function (element) {
Results.element = element;
Results.url = someurl;
},
load: function () {
$.support.cors = true;
$.ajax(
{
url: Results.url,
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
},
success: Results.onSuccess,
error: Results.onError
}
);
},
onSuccess: function (data) {
var results = data.d.results;
var html = "";
for (var i = 0; i < results.length; i++) {
html += "<div><h3><a href=\"#\">";
html += results[i].Cells.results[3].Value;
html += "</a></h3><p>"
html += results[i].Cells.results[6].Value;
html += "</p></div>";
}
Results.element.html(html);
$("#results_accordion").accordion();
},
onError: function (err) {
alert(JSON.stringify(err));
}
}
Results.init($('#results_accordion'));
Results.load();
$("#results_accordion").accordion();
}

alert() message isn't being called in my form

Firebug is giving me no error messages, but it's not working. The idea is regardless of whether the user picks an option from dropdown or if they type in something in search box, I want the alert() message defined below to alert what the value of the variable result is (e.g. {filter: Germany}). And it doesn't. I think the javascript breaks down right when a new Form instance is instantiated because I tried putting an alert in the Form variable and it was never triggered. Note that everything that pertains to this issue occurs when form.calculation() is called.
markup:
<fieldset>
<select name="filter" alter-data="dropFilter">
<option>Germany</option>
<option>Ukraine</option>
<option>Estonia</option>
</select>
<input type="text" alter-data="searchFilter" />
</fieldset>
javascript (below the body tag)
<script>
(function($){
var listview = $('#listview');
var lists = (function(){
var criteria = {
dropFilter: {
insert: function(value){
if(value)
return handleFilter("filter", value);
},
msg: "Filtering..."
},
searchFilter: {
insert: function(value){
if(value)
return handleFilter("search", value);
},
msg: "Searching..."
}
}
var handleFilter = function(key,value){
return {key: value};
}
return {
create: function(component){
var component = component.href.substring(component.href.lastIndexOf('#') + 1);
return component;
},
setDefaults: function(component){
var parameter = {};
switch(component){
case "sites":
parameter = {
'order': 'site_num',
'per_page': '20',
'url': 'sites'
}
}
return parameter;
},
getCriteria: function(criterion){
return criteria[criterion];
},
addCriteria: function(criterion, method){
criteria[criterion] = method;
}
}
})();
var Form = function(form){
var fields = [];
$(form[0].elements).each(function(){
var field = $(this);
if(typeof field.attr('alter-data') !== 'undefined') fields.push(new Field(field));
})
}
Form.prototype = {
initiate: function(){
for(field in this.fields){
this.fields[field].calculate();
}
},
isCalculable: function(){
for(field in this.fields){
if(!this.fields[field].alterData){
return false;
}
}
return true;
}
}
var Field = function(field){
this.field = field;
this.alterData = false;
this.attach("change");
this.attach("keyup");
}
Field.prototype = {
attach: function(event){
var obj = this;
if(event == "change"){
obj.field.bind("change", function(){
return obj.calculate();
})
}
if(event == "keyup"){
obj.field.bind("keyup", function(e){
return obj.calculate();
})
}
},
calculate: function(){
var obj = this,
field = obj.field,
msgClass = "msgClass",
msgList = $(document.createElement("ul")).addClass("msgClass"),
types = field.attr("alter-data").split(" "),
container = field.parent(),
messages = [];
field.next(".msgClass").remove();
for(var type in types){
var criterion = lists.getCriteria(types[type]);
if(field.val()){
var result = criterion.insert(field.val());
container.addClass("waitingMsg");
messages.push(criterion.msg);
obj.alterData = true;
alert(result);
initializeTable(result);
}
else {
return false;
obj.alterData = false;
}
}
if(messages.length){
for(msg in messages){
msgList.append("<li>" + messages[msg] + "</li");
}
}
else{
msgList.remove();
}
}
}
$('#dashboard a').click(function(){
var currentComponent = lists.create(this);
var custom = lists.setDefaults(currentComponent);
initializeTable(custom);
});
var initializeTable = function(custom){
var defaults = {};
var custom = custom || {};
var query_string = $.extend(defaults, custom);
var params = [];
$.each(query_string, function(key,value){
params += key + ': ' + value;
})
var url = custom['url'];
$.ajax({
type: 'GET',
url: '/' + url,
data: params,
dataType: 'html',
error: function(){},
beforeSend: function(){},
complete: function() {},
success: function(response) {
listview.html(response);
}
})
}
$.extend($.fn, {
calculation: function(){
var formReady = new Form($(this));
if(formReady.isCalculable) {
formReady.initiate();
}
}
})
var form = $('fieldset');
form.calculation();
})(jQuery)
Thank you for anyone who responds. I spent a lot of time trying to make this work.
The initial problem as to why the alert() was not being triggered when Form is instantiated is because, as you can see, the elements property belongs to the Form object, not fieldset object. And as you can see in the html, I place the fields as descendents of the fieldset object, not form.