I am paginating an array that I am loading page per page when I scroll to the bottom of my page. Unfortunately it seems that some chunks of my array keep coming back instead of having the newly loaded bit of array. Any idea what this is happening ??
This is my infinite_scroll_controller.js
import Rails from '#rails/ujs';
export default class extends Controller {
static targets = ["entries", "pagination"]
scroll(){
let next_page = this.paginationTarget.querySelector("a[rel='next']")
if (next_page == null) { return }
let url = next_page.href
var body = document.body,
html = document.documentElement
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
if (window.pageYOffset >= height - window.innerHeight - 100) {
console.log("bottom")
this.loadMore(url)
}
}
loadMore(url){
Rails.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: (data) => {
console.log(data)
this.entriesTarget.insertAdjacentHTML('beforeend', data.entries)
this.paginationTarget.innerHTML = data.pagination
}
})
}
}```
This is in my listing controller
``` #listings = Listing.all.sort_by { |listing| listing.created_at }.reverse!
#pagy_a, #loaded_listings = pagy_array(#listings)
respond_to do |format|
format.html
format.json {
render json: { entries: render_to_string(partial: "listings", formats: [:html]), pagination: view_context.pagy_nav(#pagy_a) }
}
end```
Related
How to scroll a down a website and take screenshot using protractor.I have attached the code I have tried.
function writeScreenShot(data: string, filename: string) {
var stream = fs.createWriteStream(filename);
stream.write(new Buffer(data, 'base64'));
stream.end();
}
// var foo = element(by.id('foo'));
//of element
//foo.takeScreenshot().then((png) => {
//writeScreenShot(png, 'foo.png');
//});
browser.executeScript('window.scrollTo(0,document.body.scrollHeight)');
//of entire page in viewport
browser.takeScreenshot().then((png) => {
writeScreenShot(png, 'foo.png');
});
I didn't see anything in the docs for pagination. Is there a built-in mechanism for this, or would I have to implement it myself?
Here is an example of pagination (Infinite scrolling) in react data grid. I am using the scrollHeight,scrollTop and clientHeight properties to check whether to load next page.You need to modify your API's to support this type of pagination.
let columns = [
{
key: 'field1',
name: 'Field1 ',
},
{
key: 'field2',
name: 'Field2 ',
},
{
key: 'field3',
name: 'Field3',
},
]
export default class DataGrid extends React.Component {
constructor(props) {
super(props)
this.state = {height: window.innerHeight - 180 > 300 ? window.innerHeight - 180 : 300,page:1}
this.rowGetter = this.rowGetter.bind(this)
this.scrollListener = () => {
if (
(this.canvas.clientHeight +
this.canvas.scrollTop) >= this.canvas.scrollHeight) {
if (this.props.data.next !== null) {
let query = {}
let newpage = this.state.page +1
query['page'] = newpage
this.setState({'page':newpage})
this.props.dispatch(fetchData(query)).then(
(res) => {
// make handling
},
(err) => {
// make handleing
}
)
}
}
};
this.canvas = null;
}
componentDidMount() {
this.props.dispatch(fetchData({'page':this.state.page}))
this.canvas = findDOMNode(this).querySelector('.react-grid-Canvas');
this.canvas.addEventListener('scroll', this.scrollListener);
this._mounted = true
}
componentWillUnmount() {
if(this.canvas) {
this.canvas.removeEventListener('scroll', this.scrollListener);
}
}
getRows() {
return this.props.data.rows;
}
getSize() {
return this.getRows().length;
}
rowGetter(rowIndex) {
let rows = this.getRows();
let _row = rows[rowIndex]
return _row
}
render() {
return (
<ReactDataGrid columns={columns}
rowGetter={this.rowGetter}
rowsCount={this.getSize()}
headerRowHeight={40}
minHeight={this.state.height}
rowHeight={40}
/>
)
}
}
Note : Assumed data are taken from redux store
I am making DOM object through javascript and i want it to render it through angularjs but it display like [object HTMLDivElement]
but in browser console its
but it renders like
.directive('attachmentify', [
function() {
return {
restrict: 'A',
scope: {
item: "#filename"
},
template: "<div ng-bind-html='content'></div>",
compile: function(iElement, iAttrs) {
return function($scope, element, attr) {
var file = $scope.item;
// console.log
// $scope.file =file;
}
},
controller: function($scope) {
var img = ['jpg', 'jpeg', 'png'];
var c = 0;
img.forEach(function(element, index) {
if ($scope.item.endsWith(element)) c++;
});
if (c) {
var div = document.createElement('div');
div.setAttribute('name', 'samundra')
div.innerHTML = "ram"
} else {
var div = document.createElement('div');
div.setAttribute('name', 'ramundra')
div.innerHTML = "sam"
}
$scope.content = div;
console.log(div);
}
}
}
])
In your controller instead of assign DOM element instance, You can set $scope.content to html
$scope.content="<div name='ramundra'>ram></div>";
I have created view model
var catalog = ko.observableArray();
$.ajax({
type: "GET",
url: "http://localhost:8080/ticket-service/rest/ticket/list",
success: function(msg) {
catalog.push.apply(catalog, $.map(msg, function(data) {
return new Ticket(data)
}));
return catalog;
},
error: function(msg) {
console.log(msg)
}
});
and the model
function Ticket(data) {
this.ticketId = ko.observable(data.ticketId);
this.ticketNo = ko.observable(data.ticketNo);
this.ticketTitle = ko.observable(data.ticketTitle);
this.longDescription = ko.observable(data.longDescription);
this.createdBy = ko.observable(data.createdBy);
this.createdOn= ko.observable(data.createdOn);
this.assignTo = ko.observable(data.assignTo);
this.priority = ko.observable(data.priority);
this.dueDate = ko.observable(data.dueDate);
this.status = ko.observable(data.status);
this.projectId = ko.observable(data.projectId);
}
with at the end viewmodel like this
return {
ticket: newTicket,
searchTerm: searchTerm,
catalog: filteredCatalog,
newTicket: newTicket,
addTicket: addTicket,
delTicket: delTicket
};
})();
console.log(vm);
ko.applyBindings(vm);
produce list,add, and delete form.The question is how can i use knockout mapping that can list from get methode.
you need to do something like this
Demonstrated taking a single entity from your code .
view:
Output Preview :
<pre data-bind="text:ko.toJSON($data,null,2)"></pre>
viewModel:
function Ticket(data) {
this.ticketId = ko.observable(data.ticketId);
}
var mapping = {
create: function (options) {
return new Ticket(options.data);
}
};
var ViewModel = function () {
var self = this;
self.catalog = ko.observableArray();
var data = [{
'ticketId': 1
}, {
'ticketId': 2
}]
//under ajax call do the same but pass 'msg' in place of data
self.catalog(ko.mapping.fromJS(data, mapping)())
console.log(self.catalog()); // check console for output
};
ko.applyBindings(new ViewModel());
sample working fiddle here
Heres the jsfiddle, jsfiddle.net/kqreJ
So I was using .bind no problem for this function but then I loaded more updates to the page and found out that .bind doesn't work for content imported to the page but just for content already on the page! Great!
So I switched it up to .delegate which is pretty cool but now I can't figure out how to .bind .unbind my function the way it was???
Function using .bind which worked perfect... except didn't work on ajax content.. :(
$('.open').bind("mouseup",function(event) {
var $this = $(this), handler = arguments.callee;
$this.unbind('mouseup', handler);
var id = $(this).attr("id");
var create = 'nope';
var regex = /\d+$/,
statusId = $('#maindiv .open').toArray().map(function(e){
return parseInt(e.id.match(regex));
});
var divsToCreate = [ parseInt(id) ];
$.each(divsToCreate, function(i,e)
{
if ( $.inArray(e, statusId) == -1 ) {
create = 'yup';
}
});
if( create == 'yup' ) {
if(id) {
$.ajax({
type: "POST",
url: "../includes/open.php",
data: "post="+ id,
cache: false,
success: function(html) {
$('.open').html(html);
$this.click(handler);
}
});
}
}
});
New function using .delegate that is not binded and creates multiple instances?
$('#maindiv').delegate("span.open", "mouseup",function(event) {
var $this = $(this), handler = arguments.callee;
$this.unbind('mouseup', handler);
var id = $(this).attr("id");
var create = 'nope';
var regex = /\d+$/,
statusId = $('#maindiv .open').toArray().map(function(e){
return parseInt(e.id.match(regex));
});
var divsToCreate = [ parseInt(id) ];
$.each(divsToCreate, function(i,e)
{
if ( $.inArray(e, statusId) == -1 ) {
create = 'yup';
}
});
if( create == 'yup' ) {
if(id) {
$.ajax({
type: "POST",
url: "../includes/open.php",
data: "post="+ id,
cache: false,
success: function(html) {
$('.open').html(html);
$this.click(handler);
}
});
}
}
});
I've spent hours trying to figure this out because I like learning how to do it myself but I had to break down and ask for help... getting frustrated!
I also read that when your binding and unbinding .delegate you have to put it above the ajax content? I've tried using .die() and .undelegate()... Maybe I just don't know where to place it?
Take a look at undelegate
It does to delegate what unbind does to bind.
In your case, I think it'd be something like:
$('#maindiv').undelegate("span.open", "mouseup").delegate("span.open", "mouseup" ...
Then you can drop the $this.unbind('mouseup', handler); within the function.