Use the browser local storage with JSF2 and Primefaces - primefaces

Hi this is not strictly a question, I would like to share my solution to use the browser local storage with JSF2 and Primefaces.
I found very little information on using local storage with jsf2 and primefaces, so it seemed useful to share my work.
The backing bean:
#Component("pocLocalStorageBean")
#Scope(WebApplicationContext.SCOPE_REQUEST)
public class PocLocalStorageBean {
private static final long serialVersionUID = 1L;
private String[] selectedCities;
private List<String> cities;
#PostConstruct
public void initialize() {
List<String> cities = new ArrayList<String>();
cities.add("Miami");
cities.add("London");
cities.add("Paris");
cities.add("Istanbul");
cities.add("Berlin");
cities.add("Barcelona");
cities.add("Rome");
cities.add("Brasilia");
cities.add("Amsterdam");
setCities(cities);
}
//GETTER E SETTER HERE
}
The page xhtml:
<h:form id="yuorFormId" cache="false">
<p:remoteCommand name="updateUiAfterLoadChoicesFromLocalStorage" update=":yuorFormId:yourSelectManyCheckboxId">
</p:remoteCommand>
<p:remoteCommand oncomplete="loadCitiesChoicesFromLocalStorage(#{pocLocalStorageBean.cities.size()});" autoRun="true">
</p:remoteCommand>
<div class="ui-g ui-fluid">
<div class="ui-g-12 ui-md-12">
<div class="card">
<p:selectManyCheckbox id="yourSelectManyCheckboxId" value="#{pocLocalStorageBean.selectedCities}" layout="responsive" columns="3">
<f:selectItems value="#{pocLocalStorageBean.cities}" var="city" itemLabel="#{city}" itemValue="#{city}"/>
<p:ajax oncomplete="setCitiesChoicesToLocalStorage(#{pocLocalStorageBean.cities.size()})"/>
</p:selectManyCheckbox>
</div>
</div>
</div>
</h:form>
And the javascript functions:
function findPreviousChoose(arrayChoicesFromLocalStorage,valueToFind){
if(arrayChoicesFromLocalStorage != null && arrayChoicesFromLocalStorage.length > 0){
var arrayLength = arrayChoicesFromLocalStorage.length;
for (var j = 0; j < arrayLength; j++) {
var iteratedChoose = arrayChoicesFromLocalStorage[j];
if(iteratedChoose!=null){
if(iteratedChoose.value == valueToFind){
return iteratedChoose;
}
}
}
}
return null;
}
function parseSafeJSON(str){
try {
if(str!=null){
var obj = JSON.parse(str);
return obj;
}
} catch (ex) {
return null;
}
return null;
}
function loadCitiesChoicesFromLocalStorage(citiesNumber){
var arrayChoicesFromLocalStorageStringed = localStorage.getItem('CITIES_LOCAL_STORE_KEY');
if(arrayChoicesFromLocalStorageStringed!=null){
var arrayChoicesFromLocalStorage = parseSafeJSON(arrayChoicesFromLocalStorageStringed);
var elementId = 'yuorFormId:yourSelectManyCheckboxId';
var element = document.getElementById(elementId);
var i;
for (i = 0; i < citiesNumber; i++) {
var elementIterated = document.getElementById(elementId+':'+i);
var valueIterated = elementIterated.value;
var previousChoose = findPreviousChoose(arrayChoicesFromLocalStorage,valueIterated);
if(previousChoose != null) {
elementIterated.defaultChecked = previousChoose.defaultChecked;
}
}
//update the needed components:
updateUiAfterLoadChoicesFromLocalStorage();
}
}
function setCitiesChoicesToLocalStorage(citiesNumber) {
var elementId = 'yuorFormId:yourSelectManyCheckboxId';
var element = document.getElementById(elementId);
var i;
var arrayChoices = new Array();
for (i = 0; i < citiesNumber; i++) {
var elementIterated = document.getElementById(elementId+':'+i);
var valueIterated = elementIterated.value;
var defaultCheckedIterated = elementIterated.checked;
var objIterated = { "value":valueIterated, "defaultChecked":defaultCheckedIterated};
arrayChoices.push(objIterated);
}
var storageValuesArray = JSON.stringify(arrayChoices);
localStorage.setItem('CITIES_LOCAL_STORE_KEY', storageValuesArray);
}
I also reported my solution to the primefaces forum:
https://forum.primefaces.org/viewtopic.php?f=3&t=39051&p=180978#p180978
If you don't use primefaces but only jsf 2.3 it shoud work with h:commandScript instead of p:remoteCommand (but I have not tried):
How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
I don't know the solution for those who use jsf < 2.3 without primefaces (any suggestions for this scenario are welcome)

Related

Simple autocomplete with Ace Editor in AS3?

I'm working in XML and I'd like to provide autocomplete suggestions for the attributes for specific node types using AS3.
For example, if the user is has a cursor in the following node:
<s:Button label="Hello World"/>
I'd like autocomplete to show "width, height, x, y".
I'm trying to get the node name and namespace and then give the editor a list of attributes that should appear in autocomplete.
I found similar questions but those are using a service call and a few that are out dated. I may delete this question if it is a duplicate.
Ace Editor for AS3 here.
In my case, for AS3, it is a combination of items:
ace.setCompleters(null); // I'm removing existing autocomplete
ace.addCompleter(codeCompleter); // adding my own
public var autoCompleteErrorMessage:String = "Nothing available";
public function codeCompleter(editor:Object, session:Object, position:Object, prefix:String, callback:Function):void {
var row:int = position.row;
var column:int = position.column;
/*
if (prefix.length === 0) {
callback(null, []);
return;
}
*/
//var myList:Array = {value: "message", caption: "Caption to user", meta: "Type shown", score: "I don't know"};
var testing:Boolean = false;
if (testing) {
callback(autoCompleteErrorMessage, [{value:"addedToStage"},{value:"added"},{value:"adding"}]);
}
else {
callback(autoCompleteErrorMessage, attributes);
}
}
protected function cursorChangeHandler(event:Event):void {
var qname:QName = getQNameFromCursorPosition(ace.row, ace.column);
if (qname==null) {
if (attributes.length) {
attributes = [];
}
return;
}
if (qname) {
attributes = getSuggestionListFromObject(classObject);
autoCompleteErrorMessage = null;
lastSelectedQName = qname;
}
}
public static var XML_TAG_NAME:String = "meta.tag.tag-name.xml";
public static var XML_TAG_OPEN:String = "meta.tag.punctuation.tag-open.xml";
public static var XML_TAG_CLOSE:String = "meta.tag.punctuation.tag-close.xml";
public static var XML_ATTRIBUTE_NAME:String = "entity.other.attribute-name.xml";
public function getQNameFromCursorPosition(row:int, column:int):QName {
var token:Object;
var line:String;
var type:String;
var value:String;
var found:Boolean;
var qname:QName;
for (; row > -1; row--) {
line = ace.getLine(row);
column = line.length;
for (; column>-1; column--) {
token = ace.getTokenAt(row, column);
type = token ? token.type : "";
if (type==XML_TAG_NAME) {
value = token.value;
found = true;
}
}
if (found) break;
}
if (found) {
qname = new QName("", value);
}
return qname;
}
The getQNameFromCursorPosition() method is fragile and I'm looking into a new method using the jumpToMatching() method.

max lengt or else dots - How or what should i write?

I want the script to show max 26 letters and if there is more I want it to make (...) <-- so that you can se there is more letters in the link.
First I put a bit of a script I have for another site containing a variable to do that, however it doesn't work in RSS:
{
temp.Add(titel);
count++;
string titel_kort = titel;
if (titel.Length > 26)
{
titel_kort = titel.Substring(0, 26) + "...";
}
}
And this is the script I want to integrate to:
#using System.Xml.XPath;
#using System.Xml;
#{
try
{
XmlTextReader udBrudRSS = new XmlTextReader("http://tidende.dk/rss.aspx");
XmlDocument doc = new XmlDocument();
doc.Load(udBrudRSS);
XmlNodeList rssItems = doc.SelectNodes("//item");
var count = 0;
foreach (XmlNode node in rssItems )
{
count++;
if (count > 3) { break; }
<div class="nyhedlink">- #node["title"].InnerText</div>
}
}
catch {}
}
You could something like this :
using (var webclient = new WebClient())
{
var data = webclient.DownloadData("http://tidende.dk/rss.aspx");
var oReader = new XmlTextReader(new MemoryStream(data));
var xml = XDocument.Load(oReader);
var values = xml.XPathSelectElements("//item").Take(3).Select(p => new
{
Link = p.XPathSelectElement("//link").Value,
Title = (p.XPathSelectElement("./title").Value.Length > 26) ?
p.XPathSelectElement("./title").Value.Substring(0, 26).Trim() + "..." :
p.XPathSelectElement("./title").Value.Trim()
});
foreach (var item in values)
{
<div class="nyhedlink">- #item.Title</div>
}
}
Sometimes is better use WebClient to make the petition instead of XmlTextReader see this question for a good explanation.

My pattern is wrong, how do I make it DRY?

So I got this TitleWindow based Flex application where these windows are called by static functions written in them.
This is how it looks like when an entity needs do be created or edited from a DataGrid:
private function incluir():void {
NavioForm.incluir(dg.dataProvider);
}
private function atualizar():void {
NavioForm.atualizar(dg.dataProvider, dg.selectedIndex);
}
It's working perfectly from this side.
But since I used static functions, the code is starting to get a bit repetitive, as we can see on the examples below:
[Script tag of a CRUD form(incluir == include, atualizar == update, excluir == delete)]
...
[Bindable] private var navio:Navio;
public static function incluir(dataList:IList):void {
var form:NavioForm = new NavioForm();
form.action = FormWindow.ACTION_NEW + Navio.name;
form.navio = new Navio();
form.navio.lastUpdate = new Date();
form.result = function():void {
PortoService.obj.persistirNavio(form.navio).result(function(navio:Navio):void {
dataList.addItem(navio);
form.close();
}).fault(function(event:FaultEvent):void {
if(event.fault.faultString == 'duplicate key') {
Util.showError("This vessel's IMO is already present in our database.");
} else throw event.fault;
});
};
PopUp.add(form);
}
public static function atualizar(dataList:IList, index:int):void {
var form:NavioForm = new NavioForm();
form.action = FormWindow.ACTION_UPDATE + Navio.name;
form.imoRecieved = true;
form.navio = dataList[index];
PortoService.obj.obter(Navio, form.navio.key).result(function(navio:Navio):void {
form.navio = navio;
form.navio.lastUpdate = new Date();
});
form.result = function():void {
PortoService.obj.persistir(form.navio).result(function(navio:Navio):void {
dataList[index] = navio;
form.close();
}).fault(function(event:FaultEvent):void {
if(event.fault.faultString == 'duplicate key') {
Util.showError("This vessel's IMO is already present in our database.");
} else throw event.fault;
});
};
PopUp.add(form);
}
...
Script tag of another CRUD form:
...
[Bindable] private var vesselType:VesselType;
public static function incluir(dataList:IList):void {
var form:VesselTypeForm = new VesselTypeForm();
form.action = FormWindow.ACTION_NEW + VesselType.name;
form.vesselType = new VesselType();
form.result = function():void {
CoreService.obj.persistir(form.vesselType).result(function(type:VesselType):void {
dataList.addItem(type);
form.close();
});
};
PopUp.add(form);
}
public static function atualizar(dataList:IList, index:int):void {
var form:VesselTypeForm = new VesselTypeForm();
form.action = FormWindow.ACTION_UPDATE + VesselType.name;
form.vesselType = Util.clone(dataList[index]);
form.result = function():void {
CoreService.obj.persistir(form.vesselType).result(function(type:VesselType):void {
dataList[index] = type;
form.close();
});
};
form.deleteClick = function():void {
CoreService.obj.excluir(form.vesselType.key).result(function():void {
dataList.removeItemAt(index);
form.close();
});
};
PopUp.add(form);
}
So, is there a design pattern or any other technique to make this work?
You could make a crud component that you instantiate with all of the dynamic stuff such as the data provider location and it broadcasts events (or signals) that you assign appropriate listeners to.

json stringify in IE 8 gives run time error Object property or method not supported

/* Problem description- I am using json stringify method to convert an javascript array to string in json notation.However I get an error message that 'Object property or method not supported' at line
hidden.value = JSON.stringify(jsonObj);
This should work as stringify is supported in IE8.Please advise
Full code below */
function getgridvalue() {
var exportLicenseId;
var bolGrossQuantity;
var bolNetQuantity;
var totalBolGrossQty =0 ;
var totalBolNetQty =0;
var jsonObj = []; //declare array
var netQtyTextBoxValue = Number(document.getElementById("<%= txtNetQty.ClientID %>").value);
var atLeastOneChecked = false;
var gridview = document.getElementById("<%= ExporterGrid.ClientID %>"); //Grab a reference to the Grid
for (i = 1; i < gridview.rows.length; i++) //Iterate through the rows
{
if (gridview.rows[i].cells[0].getElementsByTagName("input")[0] != null && gridview.rows[i].cells[0].getElementsByTagName("input")[0].type == "checkbox")
{
if (gridview.rows[i].cells[0].getElementsByTagName("input")[0].checked)
{
atLeastOneChecked = true;
exportLicenseId = gridview.rows[i].cells[8].getElementsByTagName("input")[0].value;
bolNetQuantity = gridview.rows[i].cells[5].getElementsByTagName("input")[0].value;
if (bolNetQuantity == "") {
alert('<%= NetQuantityMandatory %>');
return false;
}
if (!isNumber(bolNetQuantity)) {
alert('<%= NetQuantityNumber %>');
return false;
}
totalBolNetQty += Number(bolNetQuantity);
jsonObj.push({ ExportLicenseId: Number(exportLicenseId), BolNetQuantity: Number(bolNetQuantity) });
}
}
}
if (gridview.rows.length > 2 && !atLeastOneChecked)
{
alert('<%= SelectMsg %>');
return false;
}
if (totalBolNetQty != 0 && netQtyTextBoxValue != totalBolNetQty)
{
alert('<%= NetQuantitySum %>');
return false;
}
var hidden = document.getElementById('HTMLHiddenField');
// if (!this.JSON) {
// this.JSON = {};
// }
var JSON = JSON || {};
if (hidden != null) {
hidden.value = JSON.stringify(jsonObj);
}
}
Use the F12 Developer Tools to check the browser mode. The JSON object exists, but has no methods in IE7 mode. Use the json2 library as a fallback.
json2.js

facebook actionscript graph api - using request_ids to retrieve users

If I have used Facebook.ui() to allow the user to select a bunch of their friends, how can I use the returned request_ids array to access the friends /feeds please?
I've tried the following:
Facebook.ui("apprequests", { message:"select some friends" }, handleAppRequest, "iframe");
which allows the selection of friends to tell about the app. I then do the following:
private function handleAppRequest(result:Object):void
{
Debug.logObject(result, this, "handleAppRequest");
for (var i:int = 0; i < result.request_ids.length; i++)
{
var requestID:String = result.request_ids[i];
Facebook.api("/" + requestID, handleRequestFriends);
}
}
to select the friends returned in the result object (which I think might be where I'm going wrong), and then this returns a fail:
private function handleRequestFriends(success:Object, fail:Object):void
{
if (success) trace("success");
else trace(fail);
}
Thanks in advance
ob
EDIT: (new users can't answer their own question)
Hey again Michiel
ah i got it
it should be the following:
Facebook.ui("apprequests", { message:"select some friends" }, handleAppRequest, "iframe");
private function handleAppRequest(result:Object):void
{
for (var i:int = 0; i < result.request_ids.length; i++)
{
var requestID:String = result.request_ids[i];
Facebook.api("/" + requestID, handleRequestFriends);
}
}
private function handleRequestFriends(success:Object, fail:Object):void
{
if (success)
{
var values:Object =
{
access_token:Facebook.getSession().accessToken,
name:"This is my title",
link:"http://example.com",
picture:"http://example.com/facebook/facebooktutorial/canvas/images/icon-75x75.gif",
caption:"this is a caption",
message:"This is a test message on " + new Date().toString()
};
var friendID:String = success.to.id;
Facebook.api("/" + friendID + "/feed", handleSubmitFeed, values, URLRequestMethod.POST);
}
else
{
Debug.logObject(fail, this, "handleRequestFriends");
}
}
One question tho - can i use the facebook friend selector and just return the results without the apprequest firing off to them?
thanks
ob
i would again suggest that you use the params to send your access_token, like in your previous question :)
private function handleAppRequest(result:Object):void
{
Debug.logObject(result, this, "handleAppRequest");
for (var i:int = 0; i < result.request_ids.length; i++)
{
var requestID:String = result.request_ids[i];
var _params:Object = new Object();
_params.access_token = Facebook.getSession().accessToken;
Facebook.api("/" + requestID, handleRequestFriends, _params, "GET");
}
}
and i assume you are trying to get the user, because if you want to post to their feed, you should just use
var _params:Object = new Object();
_params.access_token = Facebook.getSession().accessToken;
_params.message = _message;
Facebook.api("/" + requestID + "/feed", handleRequestFriends, _params, "POST");
edit: btw: are you sure you are getting the right id's with this method? (haven't accessed friends list before, so i have no idea).