Change Component's content during rendering phase when loading its model fails - wicket

I have a widget components with simple markup inheritance like so
AbstractWidget
<wicket:panel>
<wicket:child />
<div wicket:enclosure="editButton" class="widget-edit-wrapper">
<button wicket:id="editButton" type="button" class="widget-edit">
<span class="glyphicon glyphicon-cog"></span>
</button>
<div style="display:none;">
<div wicket:id="editPanel" class="widget-settings"></div>
</div>
</div>
</wicket:panel>
LabelWidget
<wicket:extend>
<div wicket:id="container" class="label-widget flex-container">
<div wicket:id="label"></div>
</div>
</wicket:extend>
Now imagine the label content is taken from a loadable detachable model and loading the model throws an Exception.
I need to show some feedback to the user on this 'broken' widget component. Is there a way to replace the whole child's content when loading its model throws an Exception?
Note that LabelWidget is just one from many AbstractWidget childs so I need to solve this in the AbstractWidget and I also need to preserve all elements from the AbstractWidget component.

You can accomplish this by using a smarter model - a model that delegates to the original one and try/catches if it throws an exception. In case of an exception you will need to return an "empty" model object, where "empty" would mean different things for your different use cases.
Your smart model could implement IComponentAssignedModel so that it knows the Component it is used in. This way in the catch clause you can do component.error("..."). In AbstractWidget you should add a FeedbackPanel that will render the error message. The specialization widget, like LabelWidget, will render as "empty" (whatever this means for it) by using the fallback model.

Related

BEM css - Mix elements/modifiers

I've a question about BEM structure. Is it semantically correct to mix elements/modifiers? I have a hero and portfolio module. I want to use an portfolio__item in the hero module, but it should use the base styling of the hero__item. Is this an correct way of doing this, is it 'allowed' to mix these elements?
<section class="hero hero--collage hero--bottom-decoration">
<div class="portfolio__item hero__item hero__item--animated">
<a href="http://www.google.nl">
<div class="hero__hover">
<span class="hero__hover__content h1">Hover title</span>
</div>
<img src="http://www.google.nl" class="hero__image">
</a>
</div>
</section>
<section class="portfolio">
<div class="portfolio__item">
<a href="http://www.google.nl">
<img src="http://www.google.nl" class="hero__image">
</a>
</div>
</section>
You can do whatever you want. But BEM methodology says:
block set namespace
It's a little messy to read this.
I can't understand it at a glance.
The goal of BEM - separate blocks so you don't need write same block again. And the same for styles. With this and modifiers you can reuse and tweak every block you need.
You can mix block and elements
<img src="http://www.google.nl" class="block-name hero__image">
So on 'block-name' you can match styles for every instance. On hero__image or another element you can match unique styles.
You can't create elements of elements
You don't need write 2 lvl. Cause name of your block set namespace.
<span class="hero__hover__content h1">Hover title</span>
Just
<span class="hero__hover-content h1">Hover title</span>
docs: https://en.bem.info/methodology/naming-convention/
"Is it semantically correct to mix elements/modifiers" - I assume you want to place portfolio__item element within the hero block - it's not a good thing. You can nest a block within a block but not block's element within another block's element.
You can use modifiers to hero__item element thought like
<div class="hero__item hero__item--portfolio"></div>
which will change it's style.

Create repeatable custom form fields in web2py?

I want to create twitter bootstrap compliant form. According to the docs for Twitter Bootstrap v2.2.2 (the version included with web2py) the html should look like:
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="inputEmail">Email</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Email">
</div>
</div>
...
I'm currently using SQLFORM which outputs html that doesn't really fit with this (even using formstyle='divs'). Besides I want my html output to be clean without web2py artifacts such as class="w2p_fl". So my thought is to use a custom form. However in doing this there would be a lot of repeated code. That is, the following would basically need to be repeated for each field.
{{=form.custom.begin}}
<div class="control-group">
{{=LABEL(form.custom.label['myfield'], _class='control-label',
_for='mytable_myfield')}}
<div class="controls">{{=form.custom.widget.myfield}}</div>
</div>
...
{{=form.custom.end}}
So how can I repeat the above unit of code so I could replace it with something like {{=bootstrap_field(db.mytable.myfield)}} or some other way to adhere to DRY?
What is the web2py way to do this? Create a view function? Pass a function in the dictionary returned by the controller? Create my own html helper? Create my own widget? Another way?
If you're using Bootstrap 2, you can just do:
form = SQLFORM(..., formstyle='bootstrap')
For Bootstrap 3 (or any other custom formstyle you'd like to create), the formstyle argument can be a function (or other callable) that produces the form DOM. The function will be passed the form and a fields object, which is a list of tuples, with each tuple containing a CSS id, label, input element, and (possibly empty) comment/help text. To get an idea of what such a function should look like, check out the one used for Bootstrap 2 forms.

Does wicket lose hold of the HTML components after a rearrangement through JavaScript?

I have a repeating component in wicked which needs to be added and deleted as per the user requirement. The maximum number of component is predefined. So I am adding the components at start up and hiding and showing based on need. I am required to change the arrangement of the components in the HTML markup when there is any deletion of the component. I use JavaScript for this. I want to know if wicket would lose hold of the components if I do this.
<div wicket:id="borrowerTabs" id="borrowerTabs">
<span wicket:id="borrowerTab1" id="borrowerTab1" ></span>
<span wicket:id="borrowerTab2" id="borrowerTab2" ></span>
<span wicket:id="borrowerTab3" id="borrowerTab3" ></span>
<span wicket:id="borrowerTab4" id="borrowerTab4" ></span>
<button wicket:id="addBorrower" id="addBorrower" type="button"></button>
<button wicket:id="deleteBorrower" id="deleteBorrower" onclick="updateUIForDeleteBorrower()" type="button"></button>
</div>
If delete the borrowerTab3, contents inside borrowerTab4 will be replacing the contents inside borrowerTab3 and the model objects too will be swapped though I do not do a target.add(borrowerTab3). Now while form submission, I am not getting the values of the fields inside borrowerTab3.
I'm not sure if it helps but try component.setVisible(false) in your java code to hide it.

Dynamic String in UiBinder (not for i18n)

I'm trying to make a Widget that generalizes a bootstrap style from twitter for collapsible items.
I got to make it work hardcoding it, but I find some dificulties abstracting it.
The widget looks like:
<div class="accordion" id="accordion1">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion1" href="#collapseOne">
... text to show collapsed ...
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
... anything to show expanded ...
</div>
</div>
</div>
</div>
The thing is, this uses a javascript which depends on ids of some div tags. The generalized widget would need this to be randomized or depending on some seed passed in the constructor.
It would also be nice to have access to those generated Strings from Java part, as it would be a fancy way to set the text showing in the widget.
My first approach was to use something like <ui:with type="com.a.b.c.IdGenerator" field="idGenerator"></ui:with> but it seems to instanciate dynamically the class IdGenerator so no access to the Strings is obtained in Java part.
Is there any fancy way to dinamically generate those Strings having access to them from the Java part?
You simply need a #UiField IdGenerator idGenerator on the Java side to have the instance created by the <ui:with> injected in it (or you can #UiField(provided = true) it).

jQuery inconsistent .remove by class on element with multiple classes

I've got a page where messages and associated elements (responses, forwards, etc) all share a class based on the database id of the parent.
For example
<pre>
<div id="recentMessages">
<div id="a3" class="message a3">this is a message</div>
<div id="a5" class="message a5">this is another message</div>
</div>
<div id="recentComments">
<div id="a3" class="comment a3">this is a comment</div>
<div id="a5" class="comment a5">this is another comment</div>
</div>
<div id="recentActions">
<div id="a3" class="action a3">tim posted a new message</div>
<div id="a4" class="action a4">sara forwarded a message to john</div>
</div>
</pre>
at times I need to remove all elements with the same id, so I originally had
jQuery('div#'+id).remove();
but that would sometimes not remove all the ids because ids are supposed to be unique.
So I added the id as a class. now I use
jQuery('div.'+id).remove();
but this seems to be about 80% effective, and sometimes the divs aren't being removed.
I'm not sure if the issue is because the div has more than one class, but I need the classes because that is how I refer to the elements when somebody clicks.
For instance,
jQuery('div.message').click(function(){
get the id, send it to the server and get the message
});
is there something wrong I'm doing here? or is there a better way to do this?
Looks like this was an issue where a function was being called using a variable which had already been defined. I didn't realize this would cause a problem.
For instance:
jQuery('div','div#recentActions').click(function(){
var removeId=jQuery(this).attr('id').replace('','a');
removeDiv(removeId);
});
function removeDiv(removeId){
jQuery('div#a'+removeId).remove();
}
I can't say for sure this was the issue, but changing the function to:
function removeDiv(cancelId){
jQuery('div#a'+canceld).remove();
}
seems to be working.