[[replacing-page-elements]]
= Replacing page elements

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.



Replacing elements of the page is the most powerful general-purpose way to customize the look-n-feel of the viewer.
Examples include the
xref:vw:gmap3:about.adoc[Gmap3], xref:vw:fullcalendar:about.adoc[Fullcalendar], xref:vw:exceldownload:about.adoc[Excel Download] and xref:vw:pdfjs:about.adoc[pdf.js] components.

The pages generated by Apache Isis' Wicket viewer are built up of numerous elements, from fine-grained widgets for property/parameter fields, to much larger components that take responsibility for rendering an entire entity, or a collection of entities.
Under the covers these are all implementations of the the Apache Wicket `Component` API.
The larger components delegate to the smaller, of course.




== How the viewer selects components

Components are created using Apache Isis' `ComponentFactory` interface, which are registered in turn through the `ComponentFactoryRegistrar` interface.
Every component is categorizes by type (the `ComponentType` enum), and Apache Isis uses this to determine which `ComponentFactory` to use.
For example, the `ComponentType.BOOKMARKED_PAGES` is used to locate the `ComponentFactory` that will build the bookmarked pages panel.

Each factory is also handed a model (an implementation of `org.apache.wicket.IModel`) appropriate to its `ComponentType`; this holds the data to be rendered.
For example, `ComponentType.BOOKMARKED_PAGES` is given a `BookmarkedPagesModel`, while `ComponentType.SCALAR_NAME_AND_VALUE` factories are provided a model of type of type `ScalarModel` .

In some cases there are several factories for a given `ComponentType`; this is most notably the case for `ComponentType.SCALAR_NAME_AND_VALUE`.
After doing a first pass selection of candidate factories by `ComponentType`, each factory is then asked if it `appliesTo(Model)`.
This is an opportunity for the factory to check the model itself to see if the data within it is of the appropriate type.

Thus, the `BooleanPanelFactory` checks that the `ScalarModel` holds a boolean, while the `JodaLocalDatePanelFactory` checks to see if it holds `org.joda.time.LocalDate`.

There will typically be only one `ComponentFactory` capable of rendering a particular `ComponentType`/`ScalarModel` combination; at any rate, the framework stops as soon as one is found.

[NOTE]
====
There is one refinement to the above algorithm where multiple component factories might be used to render an object; this is discussed in xref:vw:ROOT:extending/replacing-page-elements.adoc#additional-views-of-collections[Additional Views of Collections], below.
====





== How to replace a component

This design (the http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern[chain of responsibility] design pattern) makes it quite straightforward to change the rendering of any element of the page.
For example, you might switch out Apache Isis' sliding bookmark panel and replace it with one that presents the bookmarks in some different fashion.

First, you need to write a `ComponentFactory` and corresponding `Component`.
The recommended approach is to start with the source of the `Component` you want to switch out.

The `ComponentFactory` should be annotated as a Spring service, typically using Spring's link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Service.html[@Service] annotation.

For example:

[source,java]
----
import org.springframework.stereotype.Service;

@Service
public class MyBookmarkedPagesPanelFactory extends ComponentFactoryAbstract {
    public MyBookmarkedPagesPanelFactory() {
        super(ComponentType.BOOKMARKED_PAGES);
    }
    @Override
    public ApplicationAdvice appliesTo(final IModel<?> model) {
        return appliesIf(model instanceof BookmarkedPagesModel);
    }
    @Override
    public Component createComponent(final String id, final IModel<?> model) {
        final BookmarkedPagesModel bookmarkedPagesModel = (BookmarkedPagesModel) model;
        return new MyBookmarkedPagesPanel(id, bookmarkedPagesModel);
    }
}
----

and

[source,java]
----
public class MyBookmarkedPagesPanel
    extends PanelAbstract<BookmarkedPagesModel> {
   ...
}
----

Here `PanelAbstract` ultimately inherits from `org.apache.wicket.Component`.
Your new `Component` uses the information in the provided model (eg `BookmarkedPagesModel`) to know what to render.

Your new component will be used instead of the default implementation.



[#additional-views-of-collections]
== Additional Views of Collections

As explained above, in most cases Apache Isis' Wicket viewer will search for the first `ComponentFactory` that can render an element, and use it.
In the case of (either standalone or parented) collections, though, the viewer will show all available views.

For example, out-of-the-box Apache Isis provides a table view, a summary view (totals/sums/averages of any data), and a collapsed view.
These are selected by clicking on the toolbar by each collection.

Additional views though could render the objects in the collection as a variety of ways; as illustrated by the xref:vw:gmap3:about.adoc[Gmap3], xref:vw:fullcalendar:about.adoc[Fullcalendar] and xref:vw:exceldownload:about.adoc[Excel Download] extensions.

Wicket itself has lots of components available at its http://wicketstuff.org[wicketstuff.org] companion website; you might find some of these useful for your own customizations.






== Custom object view (eg dashboard)

One further use case in particular is worth highlighting; the rendering of an entire entity.
Normally for entities this is done using `Bs3GridPanelFactory`, this being the first `ComponentFactory` for the `ComponentType.ENTITY` that is registered in Apache Isis default `ComponentFactoryRegistrarDefault`.

You could, though, register your own `ComponentFactory` for entities that is targeted at a particular class of entity - some sort of object representing a dashboard, for example.
It can use the `EntityModel` provided to it to determine the class of the entity, checking if it is of the appropriate type.

The demo app (link:https://demo-wicket.jdo.isis.incode.work[jdo] or link:https://demo-wicket.jpa.isis.incode.work[jpa]) includes an example of this technique (`Featured > Where in the World`).
