play framework-1.x pagination start at a specific position - playframework-1.x

I have a question on pagination module in Play Framework ( ver 1.x),
i have setup pagination to only show one object per page, and some other customized settings,
in the controller:
import java.util.ArrayList;
import java.util.List;
import play.modules.paginate.ValuePaginator;
import play.mvc.Controller;
public class Application extends Controller {
public static void index() {
List<String> strings = new ArrayList<String>();
strings.add("Kalle");
strings.add("Karin");
strings.add("Dixie");
strings.add("Edvin");
strings.add("Gustav");
strings.add("Axel");
int pos = 0;
for(String str : strings){
if(str.equals("Axel")){
pos += strings.indexOf(str);
break;
}
}
ValuePaginator namePaginator = new ValuePaginator(strings);
namePaginator.setPageSize(1);
namePaginator.setBoundaryControlsEnabled(false);
namePaginator.setPagesDisplayed(0);
renderArgs.put("pos", pos);
renderArgs.put("namePaginator", namePaginator);
render();
}
And in the template:
#{extends 'main.html' /}
#{set title:'Home' /}
*{#{welcome /}}*
${pos}
#{paginate.controls items:namePaginator /}
#{paginate.list items:namePaginator, as:'name'}
${name}
#{/paginate.list}
*{#{list items:strings[pos], as:'string'}
${string}
#{/list}}*
Now, as you might see in the last part of the template, there is a commented part, using the usual groovy list tag, and since it has an actual list i can force the list to start at a given position "pos", this is however not possible in the case of using the pagination.
In the case of the "items:namePaginator" it is merely a name placeholder for the underlying list and not really iterable, is there possibly a way of making the pagination start at a specified position within the wrapped list?
Thanks a lot !

I managed to solve the problem using JQuery instead of using Play Frameworks pagination module for this special case of pagination.
Principle goes like this, in the controllers action a normal Java ArrayList consisting of objects to my liking, this ArrayList is then converted to a jsonObject using the included Gson library (in Play Framework).
Gson gson = new Gson();
String jsonObj = gson.toJson(objects);
By using
renderArgs.put("jsonObj", jsonObj);
in the controller action to pass the json to the template, by the way my reason for doing all this in the first place was to be able to start "paginating" thru the objects clientside from any position in the list of objects, and to a hidden div in the template.
Next on i use JQuery to pick up the list,
$.parseJSON($('#myhiddenlist'));
And then again using JQuery to step back and forth (catching click events on anchor tags for prev and next) thru the list, and displaying the respective object per page.
Another upside of using JQuery (or javascript for that matter), is that i don't have to worry about page reload, as is the case with Play Frameworks pagination module.
JQuery-part
$(function(){
var ourlist = $('#ourlist').text();
var jsonOur = $.parseJSON(ourlist);
var length = jsonOur.length;
var pos = parseInt($('#ourpos').text());
var showList = $('#showlist');
showList.append(jsonOur[pos].name);
initControls();
function hasPrev(){
if(pos > 0){
return true;
}else{
return false;
}
}
function hasNext(){
if(pos < (length - 1)){
return true;
}else{
return false;
}
}
function showItem(pos){
showList.empty();
showList.append(jsonOur[pos].name);
}
$('.previous a').click(function(e){
if(hasPrev()){pos--;}
if(hasPrev()){
$('li.next').removeClass('off');
$('li.next a').css('color', 'blue');
}else{
$('li.previous').addClass('off');
$('li.previous.off a').css('color', 'grey');
}
showItem(pos);
});
$('.next a').click(function(e){
if(hasNext()){pos++;}
if(hasNext()){
$('li.previous').removeClass('off');
$('li.previous a').css('color', 'blue');
}else{
$('li.next').addClass('off');
$('li.next.off a').css('color', 'grey');
}
showItem(pos);
});
function initControls(){
if(hasNext()){
$('li.previous').removeClass('off');
}else{
$('li.next').addClass('off');
$('li.next.off a').css('color', 'grey');
}
if(hasPrev()){
$('li.next').removeClass('off');
}else{
$('li.previous').addClass('off');
$('li.previous.off a').css('color', 'grey');
}
}
//for testing only
function showPos(pos){
console.log(pos);
}
});
HTML part
#{extends 'main.html' /}
#{set title:'Home' /}
#{content.rightside Pos: pos /}<!-- loads the side content -->
<div id="ourlist" class="hide">${jsonOurList}</div>
<div id="ourpos" class="hide">${pos}</div>
<ul class="pagination">
<li class="previous">Prev</li>
<li class="next">Next</li>
</ul>
<div id="showlist"></div>
CSS part
ul.pagination li {
display: inline;
}
ul.pagination li a {
outline: none;
text-decoration: none;
}
li.previous.off a,
li.next.off a {
color: grey;
cursor: default;
}
li.previous a,
li.next a {
color: blue;
cursor: pointer;
}
.hide {
display: none;
}
Ok, so this is not really a solution for tweaking the Play module, but a more pragmatic approach, using JQuery.
Hope this might help anyone having a similar problem.
//Kalle

Related

How to replace `#computed` with setter returning new value with new native setters?

Problem
I've often used this kind of computed properties where the setter simply returns the new value :
#computed('args.myValue')
get myValue() {
return this.args.myValue;
}
set myValue(newValue) {
return newValue; // <==== this is no longer valid with native setter
}
This does few things :
Set initial value to args.myValue
Allow to change the value (typically through an <Input #value={{this.myValue}} />)
Restore the default value when args.myValue changes
The problem comes with native setters which can't return any value.
Notice I could probably find a "hackish" solution but I'd like to have code that follows new EmberJS conventions in order to avoid painfull later updates.
Things I tried
Manual caching
#tracked _myValue = null;
get myValue() {
return this._myValue || this.args.myValue;
}
set myValue(newValue) {
this._myValue = newValue;
}
This does not work because _myValue is always set after the first myValue=(newValue).
In order to make it work, there should be some kind of observer which resets it to null on args.myValue change.
Sadly, observers are no longer part of EmberJS with native classes.
{{unbound}} helper
<Input #value={{unbound this.myValue}} />
As expected, it does not work because it just doesn't update myValue.
{{unbound}} helper combined with event.target.value handling
<Input #value={{unbound this.myValue}} {{on "keyup" this.keyPressed}} />
get myValue() {
return this.args.myValue;
}
#action keyPressed(event) {
this.doStuffThatWillUpdateAtSomeTimeMyValue(event.target.value);
}
But the Input is still not updated when the args.myValue changes.
Initial code
Here is a more concrete use example :
Component
// app/components/my-component.js
export default class MyComponent extends Component {
#computed('args.projectName')
get projectName() {
return this.args.projectName;
}
set projectName(newValue) {
return newValue; // <==== this is no longer valid with native setter
}
#action
searchProjects() {
/* event key stuff omitted */
const query = this.projectName;
this.args.queryProjects(query);
}
}
{{! app/components/my-component.hbs }}
<Input #value={{this.projectName}} {{on "keyup" this.searchProjects}} />
Controller
// app/controllers/index.js
export default class IndexController extends Controller {
get entry() {
return this.model.entry;
}
get entryProjectName() {
return this.entry.get('project.name');
}
#tracked queriedProjects = null;
#action queryProjects(query) {
this.store.query('project', { filter: { query: query } })
.then((projects) => this.queriedProjects = projects);
}
#action setEntryProject(project) {
this.entry.project = project;
}
}
{{! app/templates/index.hbs }}
<MyComponent
#projectName={{this.entryProjectName}}
#searchProjects={{this.queryProjects}} />
When the queriedProjects are set in the controller, the component displays them.
When one of those search results is clicked, the controller updates the setEntryProject is called.
According to this Ember.js discussion :
Net, my own view here is that for exactly this reason, it’s often better to use a regular <input> instead of the <Input> component, and to wire up your own event listeners. That will make you responsible to set the item.quantity value in the action, but it also eliminates that last problem of having two different ways of setting the same value, and it also gives you a chance to do other things with the event handling.
I found a solution for this problem by using standard <input>, which seems to be the "right way" to solve it (I'll really appreciate any comment that tells me a better way) :
{{! app/components/my-component.hbs }}
<input value={{this.projectName}} {{on "keyup" this.searchProjects}} />
// app/components/my-component.js
#action
searchProjects(event) {
/* event key stuff omitted */
const query = event.target.value;
this.args.queryProjects(query);
}
If I needed to keep the input value as a property, I could have done this :
{{! app/components/my-component.hbs }}
<input value={{this.projectName}}
{{on "input" this.setProjectQuery}}
{{on "keyup" this.searchProjects}} />
// app/components/my-component.js
#action setProjectQuery(event) {
this._projectQuery = event.target.value;
}
#action
searchProjects( {
/* event key stuff omitted */
const query = this._projectQuery;
this.args.queryProjects(query);
}
EDIT
Notice the following solution has one downside : it does not provide a simple way to reset the input value to the this.projectName when it does not change, for example after a focusout.
In order to fix this, I've added some code :
{{! app/components/my-component.hbs }}
<input value={{or this.currentInputValue this.projectName}}
{{on "focusin" this.setCurrentInputValue}}
{{on "focusout" this.clearCurrentInputValue}}
{{on "input" this.setProjectQuery}}
{{on "keyup" this.searchProjects}} />
// app/components/my-component.js
// previous code omitted
#tracked currentInputValue = null;
#action setCurrentInputValue() {
this.currentInputValue = this.projectName;
}
#action clearCurrentInputValue() {
this.currentInputValue = null;
}
There is a quite generic and concise approach to this 2-source binding scenario with any interactive input element and beyond.
Considering your first attempt (»Manual Caching«):
we have a functional feedback loop through the getter and setter; no return value from the setter is required since it unconditionally triggers a bound getter (this._myValue doesn't need to be tracked)
a switch is needed to let a changing external preset value (this.args.myValue) inject into this loop
this is accomplished by a GUID hashmap based on the preset value that establishes a transient scope for the interactive input; thus, changing preset value injections and interative inputs overwrite each other:
// app/components/my-component.js
import Component from '#glimmer/component';
import { guidFor } from '#ember/object/internals';
export default class extends Component {
// external preset value by #stringArg
_myValue = new Map();
get myValue() {
let currentArg = this.args.stringArg || null;
let guid = guidFor(currentArg);
if (this._myValue.has(guid)) {
return this._myValue.get(guid)
}
else {
this._myValue.clear(); // (optional) avoid subsequent GUID reuse of primitive types (Strings)
return currentArg;
}
}
set myValue(value) {
this._myValue.set(guidFor(this.args.stringArg || null), value);
}
}
// app/components/my-component.hbs
<Input #value={{mut this.myValue}} />
https://ember-twiddle.com/a72fa70c472dfc54d03d040f0d849d17

emberjs + gojs integration

Hey guys I am trying out emberjs and want to integrate goJS to it. I did an npm install of the package https://www.npmjs.com/package/gojs
But I can't find any good documentation on this.. so if anyone can point out my error that will be great
import Component from "#glimmer/component";
import go from "gojs";
import { action } from "#ember/object";
import { tracked } from "#glimmer/tracking";
export default class GraphComponent extends Component {
#tracked iconName = "check-circle";
$ = go.GraphObject.make;
myDiagram = $(go.Diagram, "myDiagramDiv");
#action
changeIcon() {
if (this.iconName == "check-circle") {
this.iconName = "sync-alt";
} else {
this.iconName = "check-circle";
}
}
}
This is my ember component graph.js and In graph.hbs I have the corresponding div but some how nothing shows up on the screen. am I missing something ?
And would also appreciate any links to a goJS with emberJS docs.TY
I would recommend to utilize the didInsert render modifier.
With this you can do
<div id="myDiagramDiv" {{did-insert this.insertDiagram}}></div>
and then you can have an action that will run after the div was inserted to the DOM:
#action
insertDiagram() {
const $ = go.GraphObject.make;
const myDiagram = $(go.Diagram, "myDiagramDiv");
}
otherwise you will run this code before the <div> is avaliable.

ionic2 - Google maps not working in Browser

Its code below that I use to show map in my page.
ts file
import {
GoogleMaps,
GoogleMap,
GoogleMapsEvent,
LatLng,
CameraPosition,
MarkerOptions,
Marker
} from '#ionic-native/google-maps';
export class MapPage {
constructor(private googleMaps: GoogleMaps){}
ngAfterViewInit() {
this.loadMap();
}
loadMap() {
let element: HTMLElement = document.getElementById('map');
let map: GoogleMap = this.googleMaps.create(element);
map.one(GoogleMapsEvent.MAP_READY).then(() => {
console.log('Map is ready!');
});
}
}
Html code block
<div #map id="map" style="height:100%;"></div>
Since you're using Google Maps from Ionic Native, it won't work on the browser. Ionic Native/Cordova plugins work only in a simulator / real device only

React/Jasmine/Karma/Phantom Unit Test: findDOMNode and renderIntoDocument not working as expected

I'm trying to write a simple unit test and can't seem to figure it out. I want to test a bootstrap modal to ensure it displays the correct contents when I pass certain object properties to it. Here's what my modal code looks like:
import React, { Component, PropTypes } from 'react';
import { Button, Modal } from 'react-bootstrap';
class ModalBox extends Component {
render() {
const { modalBox } = this.props;
let content;
if (modalBox.contentBody) {
content = modalBox.contentBody;
} else {
content = (
<span>
<Modal.Header closeButton onHide={this.close.bind(this)}>
<Modal.Title>{modalBox.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
{modalBox.message}
</Modal.Body>
{modalBox.isConfirm &&
<Modal.Footer>
<Button onClick={modalBox.onCancel} className="modal-button cancel">{modalBox.cancelText || 'Cancel'}</Button>
<Button onClick={modalBox.onConfirm} className="modal-button confirm">{modalBox.confirmText || 'Confirm'}</Button>
</Modal.Footer>
}
</span>
);
}
return (
<Modal show={typeof modalBox != 'undefined'} onHide={this.close.bind(this)} dialogClassName={modalBox.dialogClassName || ''} backdrop={modalBox.backdrop || true}>
{content}
</Modal>
);
}
}
So for a test, I want to make sure that if I pass the prop modalBox containing the contentBody field that it just returns the contentBody for the modal body. Here's an example of what I'm trying to test:
it("renders only contentBody when provided", () => {
let modalBoxObj = {
contentBody: <div className="test-content-body">This is a test.</div>
};
let element = React.createElement(ModalBox, {modalBox: modalBoxObj});
let component = TestUtils.renderIntoDocument(element);
let modalWrapper = TestUtils.scryRenderedDOMComponentsWithClass(component, 'modal');
// modalWrapper returns an empty array, so this returns "Expected 0 to be 1"
expect(modalWrapper.length).toBe(1);
let testBody = TestUtils.scryRenderedDOMComponentsWithClass(component, 'test-content-body');
// testBody returns an empty array, so this returns "Expected 0 to be 1"
expect(testBody.length).toBe(1);
// this returns "TypeError: 'undefined' is not an object (evaluating 'testBody[0].innerHTML')"
expect(testBody[0].innerHTML).toEqual("This is a test.");
}
I've also tried doing shallow rendering with TestUtils.createRenderer and trying that approach, but had no luck with it. Based on the examples I've seen online and previous testing experience with react <0.14, I feel this test should work. I just don't know what I'm missing or misunderstanding. In the past, I did something like below and just looked at the componentNode object to find elements and such, but componentNode is returning null.
let component = TestUtils.renderIntoDocument(element);
let componentNode = findDOMNode(component);
Thanks for your help!
The solution ended up being to add a ref to the ModalBox component. Once added, we were able to target the node like this:
let component = TestUtils.renderIntoDocument(<ModalBox modalBox={modalBoxObj} />);
let componentNode = findDOMNode(component.refs.modalBox._modal);

How do you handle pluralisation in Ember?

Are there any helpers for making templates aware of when to use plural words?
In the example below, how do you make the template output "2 dogs have..."?
The code:
Ember.View.create({dog_count: 2})
The template:
{{dog_count}} (dog has)/(dogs have) gone for a walk.
I know this is old, but I needed it today, so here goes.
Ember.Handlebars.registerBoundHelper('pluralize', function(number, opts) {
var single = opts.hash['s'];
Ember.assert('pluralize requires a singular string (s)', single);
var plural = opts.hash['p'] || single + 's';
return (number == 1) ? single : plural;
});
Usage:
{{questions.length}} {{pluralize questions.length s="Question"}}
or
{{dog_count}} {{pluralize dog_count s="dog has" p="dogs have"}} gone for a walk.
The plural (p=) option is only necessary when you don't want the standard +s behavior.
There is a I18n library for Ember: zendesk/ember-i18n.
There is a handlebars helper t which handles the internationalization by looking up string from Em.I18n.translations:
Em.I18n.translations = {
'dog.walk.one': '1 dog has gone for a walk.',
'dog.walk.other': '{{count}} dogs have gone for a walk.'
};
And you can then use the string in your Handlebars template via:
{{t dog.walk countBinding="dogCount"}}
The code above is untested and just taken from the documentation in the README.
Another JS I18n library I found is Alex Sexton's messageformat.js.
It depends on the complexity of you app, but you can also use a computed property for that, see http://jsfiddle.net/pangratz666/pzg4c/:
Handlebars:
<script type="text/x-handlebars" data-template-name="dog" >
{{dogCountString}}
</script>​
JavaScript:
Ember.View.create({
templateName: 'dog',
dogCountString: function() {
var dogCount = this.get('dogCount');
var dogCountStr = (dogCount === 1) ? 'dog has' : 'dogs have';
return '%# %# gone for a walk.'.fmt(dogCount, dogCountStr);
}.property('dogCount')
}).append();
If you use Ember Data you can use Ember.Inflector.
var inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
inflector.pluralize('person') //=> 'people'
You can register a new helper with:
Handlebars.registerHelper('pluralize', function(number, single) {
if (number === 1) { return single; }
else {
var inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
return inflector.pluralize(single);
}
});
More details at http://emberjs.com/api/data/classes/Ember.Inflector.html
It looks like you got an answer from wycats himself, but I didn't see it mentioned in this thread, so here it is:
Handlebars.registerHelper('pluralize', function(number, single, plural) {
if (number === 1) { return single; }
else { return plural; }
});
I recently found this library http://slexaxton.github.com/Jed/ which seems to be a nice tool for JS i18n. I guess you can pretty easily create your own implementation by registering a handlebars helper using this library.
I do not know of any Ember specific functions that will do this for you. However, generally when you pluralize a word, the single version only shows up when the count is one.
See this for an example: http://jsfiddle.net/6VN56/
function pluralize(count, single, plural) {
return count + " " + (count == 1 ? single : plural);
}
pluralize(1, 'dog', 'dogs') // 1 dog
pluralize(10, 'dog', 'dogs') // 10 dogs
pluralize(0, 'dog', 'dogs') // 0 dogs