JSF 2.2 Multi Select Custom Component - jsf-2

To support our organization's component library, I would like to create an enhanced selectManyMenu. A requirement is that it resemble the type that features a dropdown menu, whose menu items have checkboxes showing whether they are selected. On top of this, I would like the the top row of the drop down, the area that is always visible to show 'bubbles' for lack of a better term, containing the label of the selected item as well as an 'X' button to remove each one, similar to a 'tag' widget.
I would like to create a JSF custom component, rather than decorating the existing <h:selectManyMenu> with some jQuery plugin that hides it and renders its own widget with a bunch of obfuscated javascript that I have no idea how it works. To be honest, none of the ones I've found fit in very well with our UI, and fundamentally I don't feel as though that is good use of JSF, to slop in some jQuery widget when JSF has such robust custom component features.
To get to my current problem, I have a custom component class set up that extends UIInput and provides the encode*() methods to render a <select> with its <option> tags same as an <h:selectManyMenu> does. I'm having a problem with the decode() method:
#Override
public void decode(FacesContext context) {
Map<String, String> requestParams = context.getExternalContext().getRequestParameterMap();
String clientId = getClientId();
Object param = requestParams.get(clientId);
LOG.debug("param: {}", param);
}
The issue is param ends up being a single string no matter how many items I select. I have verified on the front end the exact same POST request is sent when I use <h:selectManyMenu>, so I am guessing I have to do something different in decode() to all of the values from the request.
For bonus points, can anyone point me to some concise explanation of the source code for, say, even just <h:inputText>. I am able to browse the source for the JSF implementation we are using, Mojarra, but it gets extremely hard to follow since it uses separate renderers, and all sorts of factories and things to select which renderer to use, etc. I have gotten by so far by leaning on composite components, with backing components when necessary, but this one and a few others coming down the pipe I think are beyond what composite components can be used effectively for.
Also, is this the best approach to accomplish what I'm after? Would I be better off creating a custom renderer for the existing <h:selectManyMenu>? That seems like an even more elegant solution since this component basically IS a selectManyMenu just rendered a little differently and having a bit of javascript on the front end.

I gather your question boils down to:
How can I obtain a request parameter with multiple values in JSF?
The answer is: use ExternalContext#getRequestParameterValuesMap().
#Override
public void decode(FacesContext context) {
Map<String, String[]> requestParamValues = context.getExternalContext().getRequestParameterValuesMap();
String clientId = getClientId(context);
String[] params = requestParamValues.get(clientId);
// ...
}
but it gets extremely hard to follow since it uses separate renderers, and all sorts of factories and things to select which renderer to use, etc
Not sure, but perhaps you're looking for What is the relationship between component family, component type and renderer type? or How do I determine the renderer of a built-in component.
Would I be better off creating a custom renderer for the existing <h:selectManyMenu>? That seems like an even more elegant solution since this component basically IS a selectManyMenu just rendered a little differently and having a bit of javascript on the front end.
Makes indeed more sense.

Related

How to get a reference to a particular component in an Angular2 template?

I know that Angular2 has #ViewQuery to get a QueryList of components matching the given type. But is there a way to get a reference to a particular component in this QueryList?
Right now, the only way I can think to do this is to give the component an extra "id" field, then iterate through the QueryList and check if the identifier is the one I want, e.g.:
getComponentById(QueryList<HasIdField> queryList, String id) =>
queryList.singleWhere((component) => component.id == id);
But this seems like a common enough problem that it seems like there should be a way to do this without adding this "id" boilerplate. I know that a component can be referenced locally within a template using #, but is there a way to reference a component similarly within a class?
Currently this functionality does not exist, see here for details on why the functionality to implement a custom filter is currently on hold due to potential performance reasons.
So the way you are doing it seems to be the right way given the functionality that is available currently, but this might change as the framework is now in alpha.

Is there any way to add class to input using FluentBootstrap?

#form.EditorFor().AddAttributes(new {#class="class"}) makes a div wrapper with added attributes, is there any way to actually add class to input itself instead of wrapping it around?
Sorry it took so long for me to find this - still not used to coming on StackOverflow and searching for my libs :).
Unfortunately, you can't do what you want to at this time. As far as I know, you wouldn't be able to do it in straight ASP.NET MVC either.
The problem is that calling EditorFor() really just farms out to an editor template (Scott Hanselman has a nice little real-world example on his blog). Depending on the model property type, the editor template could have an <input>, or it could have a <textarea>, or it could have a whole bunch of form elements for a really complex editing experience. Since we don't know what the EditorFor() might return, we have no way of knowing to which element, or even if, the extra attributes should be applied.

Orchard CMS conditionally hide widget and suppress zone

I am trying to conditionally suppress a widget from its driver. I basically have logic that if met, should display the widget and if not, should suppress it. The widget loads properties from the current page content item, and based on some properties should display or hide. I've got all the logic working, the only part left is suppressing the actual output.
I've tried returning null from the driver, however this simply outputs an empty widget (with its wrapper). How do I completely remove the widget from view?
Finally, the zone that this widget is placed in should suppress if none of the conditional widgets display.
Is this type of flexibility possible in Orchard? Preferably from my custom module not my theme, I'm trying to separate functionality from styling.
EDIT:
Here is the context of my situation and what I am trying to accomplish. I'm sure there is a much cleaner way to do this within Orchard than how I have naively designed it the first go-around: My client's copywriters tag pages as they see fit (using the Tags module/part). I have created 2 custom content types, "Testimonials" and "Offers", both with tags themselves among other properties [these are managed by a different team of copywriters].
On most "inner pages" of the website (I'm using a layer to determine the appropriate pages), the page's sidebar gets a "Testimonial" widget and a "Offer" widget. These widgets both operate the same, although independently of each other:
They grab the tags of the current page, then pull a random [Testimonial|Offer] that has any matching tags as well. There are 4 cases that can happen given any inner page: a testimonial is displayed and the offer is hidden (testimonial tag matched, offer tag didn't), the testimonial is hidden and the offer is displayed, both the testimonial and offer displays, and finally neither displays. The first 3 use cases are working great, the 4th is what I'm having difficulty with, as the sidebar [zone] still displays even if both widgets do not (returning null from their respective drivers).
A bit of context about widgets: widgets are supposed to be pieces of contents that are visible on some or all pages of the site, and that provide information that is not directly related to the main content item on the page (if there is such a thing).
As a consequence, what you are describing should not be implemented as widgets (all that you had to do to make it work attests to that further), because they are really part of the content item. Instead, you should have implemented a part or a field. You can then simply place the shape for this part of field, using placement, by specifying a top-level zone: <place the_shape_name="/the_zone_where_you_want_it:1"/>
Unfortunately I've had to use a bit of a hack so that I could move on with the project as I'm under an aggressive deadline, but if there is a better method and/or solution I'll test as I get the chance and mark as the answer.
To get it to work, I overwrote the Widget.Wrapper.cshtml file within my theme. There, I assigned a variable to the Display(Model.Child) call, and if the result is an empty string simply return. This removes any empty widget wrapping tags. (I personally feel Orchard should behave this way by default):
var child = Display(Model.Child);
// -- NOTE: shape tracing breaks this logic!
if (string.IsNullOrWhiteSpace(child.ToString())) {
return;
}
Then simply replace the #Display(Model.Child) between the header and footer with #(child)
I then added the following method to my Layout.cshtml file.
Func<dynamic, IHtmlString> CollapsableZone = x =>
{
var display = Display(x);
string zoneName = x.ZoneName;
if (string.Equals(display.ToString(), string.Format("<div class=\"zone zone-{0}\"></div>", zoneName.HtmlClassify()), StringComparison.CurrentCultureIgnoreCase))
{
return new HtmlString(string.Empty);
}
return display;
};
Simple function that assigns the display call to a variable, checks if it is an empty zone tag, and returns. I then create variables for each zone assigned to the value of the function above. I replace all the #if (Model.ZoneName != null) with #if (!string.IsNullOrWhiteSpace(zoneVariable)), and replace the calls to #Zone(Model.ZoneName) with #(zoneVariable).
This is working for the time being. It is quite a hack and brittle solution but I've had to move on to other things.

Wrong selected option for selectOneMenu with POJOs and Converter

in our company we're hitting a serious problem which we think is a serious design flaw of the JSF spec, if it is the normal behavior.
This is our usecase:
SelectOneMenu (standard JSF or primefaces, doesn't matter, same behavior)
SelectItems with a database entity as it's value and a string as the label
A converter (via attribute on the selectOneMenu) which translates the entity to its ID (getAsString) and from the ID to the entity (getAsObject)
Everything works as expected as long as the entity inside the value attribute of the selectOneMenu is loaded using the same entityManager as the entities inside the selectItems. We have the same POJOs and therefore the same hashcode (Object#equals() returns true). But as soon as one of the entities is loaded via a different entityManager and therefore has a different hashcode, we are never able to get a match to generate the expected selected attribute of an select item (HTML <option /> ).
The cause of this behavior is, that the JSF-impl and primefaces both use the POJOs in the call
boolean selected = isSelected(context, menu, itemValue, valuesArray, converter);
for itemValue and valuesArray. The implementation of isSelected relies on Object#equals() for POJOs. In my opinion it should always use the value of Converter#getAsString if we have a Converter and pass it to isSelected. This is also the behavior for a POST request. Here we got a submittedValue for the selectOneMenu which is compared to the converted value of the POJO (Converter#getAsString).
Now the question:
Is this the expected behavior as it's described in the spec? Isn't the output of the converter the better way to handle this comparision? Now we have to modify our entity classes and overwrite the equals method to be able to use this construct.
Your mistake is that you forgot to implement/autogenerate equals() (and hashCode()) method conform the contract. This is beyond control of JSF. Pointing the accusing finger to JSF isn't making any sense.
It's handy to have a base entity where all your entities extend from so that you don't need to repeat the task over all entities (even though the average IDE/tool can easily autogenerate them). You can find an elaborate example in 2nd "See also" link.
See also:
Validation Error: Value is not valid
Implement converters for entities with Java Generics
I believe that this is the correct behavior. On Java side the values of the component and selection are POJOs. You have full control of the logic of their equality etc. It should not matter how it is converted to UI display and back. As a component user you should not bother to know how the POJO is displayed. As text, icon, color, whatever. The Java side of the component undestands and communicats with POJOs
YOUR CODE ----------> JAVA COMPONENT --------> CONVERTER ----------> HTML
Also I guess that relying on reference equality for entities is a road to problems. Setting equals/hashCode to use actual ID is the best approach.

MVC reusable propertygrid

In my web application framework (currently WebForms) I have a control that behaves like a classic propertygrid. It is initialized with an object ID (database key), then it reads metadata to determine the type of the object and the attributes of the object. It displays the attributes, string attributes as textboxes, bool attributes as checkboxes, enum attributes as dropdown lists. On page submit there is a method of the control ctrl.SaveData() that saved the changed attribute values back to the database.
The WebForm control tree and event model supports this approach quite nicely. Now I am asking myself if it is possible to achieve a similar solution for ASP.NET MVC. The main objective is to have a generic, reusable component that can be applied in a variety of situations with not much hassle. Additionally the solution must be flexible enough to put multiple instances of the component for multiple objects on a single page. Here the auto-generated WebForms HTML IDs also helped.
I am very curious about your ideas! Thanks a lot for answering!
You could achieve this effect using a custom ViewModel that contains enough metadata to identify the object being edited/saved. You would use this in conjunction with a partial view that renders the ViewModel. The main page would use the metadata in the ViewModel to either direct the post to a specific controller action to save that particular object or pass the metadata back to a common action (as hidden inputs, perhaps) in order that that action can choose the proper table in which to persist the data.
Personally, I would not take this approach. My feeling is that the more general you make a view/action, the more work it becomes to adapt it for different circumstances. I have done similar things for viewing sets of objects, but for a detail view or editing I like to work with more specific models and views.

Resources