Skip to content

OrienteerBAP/vuecket

Repository files navigation

vuecket

Power of Vue.JS married with magic of Apache Wicket

Vuecket allows to be reactive on frontend and backend without coding of REST services.

Content

  1. Progress and Plans
  2. Guiding Principles
  3. Enabling Vuecket
  4. Association of Wicket and Vue Components
  5. Server-side methods
  6. Subscribing to Vue Events
  7. Watch data changes
  8. Data Fibers

Other documentation:

Current Progress and Plans

  • Loading of Vue components code
    • From JSON configuration
    • From Vue files
    • From NPM packages
  • Support of propogation of Vue events to server side: $on, $once, $watch
  • Support of data channels between server side and client
    • One Time - upon Vue component load
    • Observe - push changes to server side IMobel if they are changed on client one
    • Periodical refresh from server side
    • WebSocket based refresh from server side
  • Support of server based Vue methods

Guiding Principles

Vuecket idealogy following the following principals:

  1. Be declarative, not imperative
    • You can use VueJS 3rd party libraries and get benefits out of Vuecket even without modifying them
    • In a similar way, you can use 3rd party Apache Wicket component and just by adding VueBehavior (Behavior provided by Vuecket) you enable Vuecket benefits
  2. Provide 80% of functionality Out Of the Box, but do have good extension points for the remaining 20%

As you can see, btw, both Vue.Js and Apache Wicket fit this Guiding Principles as well.

Enabling Vuecket

Add the following dependency into your pom.xml:

<dependency>
   <groupId>org.orienteer.vuecket</groupId>
   <artifactId>vuecket</artifactId>
   <version>${project.version}</version>
</dependency>

If you are using SNAPSHOT version, please make sure that the following repository is included into your pom.xml:

<repository>
	<id>Sonatype Nexus</id>
	<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
	<releases>
		<enabled>false</enabled>
	</releases>
	<snapshots>
		<enabled>true</enabled>
	</snapshots>
</repository>

Association of Wicket and Vue Components

To start using of Vuecket power you should associate your server-side component(Wicket) and client-side component(Vue.js). You have 2 ways how to do that:

  • either through Annotations
  • or java code.

Vue.js components can be also defined by:

  • JSON description
  • VUE file
  • NPM package

Annotations

The following code will allow you to make from common Wicket Label component which supports Markdown

@VueNpm(packageName = "vue-markdown", path = "dist/vue-markdown.js", enablement = "Vue.use(VueMarkdown)")
public class VueMarkdown extends Label {

	public VueMarkdown(String id, IModel<?> model) {
		super(id, model);
	}

	public VueMarkdown(String id, Serializable label) {
		super(id, label);
	}

	public VueMarkdown(String id) {
		super(id);
	}
	
	@Override
	protected void onComponentTag(ComponentTag tag) {
		tag.setName("vue-markdown");
		super.onComponentTag(tag);
	}
}

Check the following annotations: @VueJson, @VueFile and @VueNpm

Directly on Wicket Componet

add(new VueComponent<String>("app")
      .setVueDescriptor("{ data: { message : 'Hello Vue'}}")
);

add(new VueComponent<String>("app2")
      .setVueDescriptor(new PackageResourceReference(HomePage.class,"HomePage.app2.vue"))
);

add(new Label("app3").add(new VueBehavior(new VueJsonDescriptor("{ data: { message : 'Hello Vue'}}"))));

Server-side methods

Vuecket can work transparantly for Vue code. But you can add more spice by invoking server based methods from your Vue code.

There are 2 ways how you can use Vuecket server methods:

  • vcInvoke - asynchronous invokation of server method. No reply from server expected. But server side method has possiblity to "push" some changes to the client side, if needed.
  • vcCall - return Promise which will contain response from server side

Example from test Vuecket application:

add(new VueComponent<Object>("app5") {
	@VueMethod("count")
	public void updateCountModel(IVuecketMethod.Context ctx, int count) {
		IVuecketMethod.pushDataPatch(ctx, "server", "Hello from server #"+count);
	}
}.setVueDescriptor("{ data: { count : 0, server: 'Hello from client side' }}"));
<div>
	<h1>App #5</h1>
	<div wicket:id="app5">
		<button @click="count++; vcInvoke('count', count)">Clicked {{count}} times</button>
		{{ server }}
	</div>
</div>

Subscribing to Vue Events

It might be helpful to subscribe to particular Vue Events on server side. To do that you can use @VueOn and @VueOnce annotations for methods which needs to be invoked if event occur on client side. Example:

@VueOn("increase")
public void showIncrease(int count) {
	System.out.println("On Increase called. Recieved count = "+count);
}
<button @click="$emit('increase', count)">Test Emit</button>

Watch data changes

In the similiar way you can subscribe server side method to changes of data on client side by using @VueWatch annotation

@VueWatch("count")
public void countChanged(Integer newCount, Integer oldCount) {
	System.out.println("Count changed from "+oldCount+" to "+newCount);
}
<button @click="count++">Clicked {{count}} times</button>

Data Fibers

Data fiber is a way to synchronize data between server side and browser. There are different types of data-fibers

  • load - data will be provided only for initial Vue component loading
  • observe - data will be sent back to server upon any change
  • refresh - data periodically checked for changes and if there are any - they will be uploaded
  • wspush - data pushed to client server through WebSocket if there are changes (NOT YET SUPPORTED)

Example:

//Value of this model will be initially load to all connected clients and then kept update upon changes
private static final IModel<String> HELLO_MODEL = Model.of("Hello from server");
...
VueComponent<Object> app6 = new VueComponent<Object>("app6", HELLO_MODEL)
				.setVueDescriptor("{ data: { text : 'Hello Vue'}}")
				.addDataFiber("text");  // <===Pay attention to this call. It binds default IModel to 'text' data fiber
app6.add(new VueMarkdown("markdown", ""));
add(app6);
<div>
	<h1>App #6</h1>
	<div wicket:id="app6">
		<textarea v-model="text"></textarea>
		<vue-markdown wicket:id="markdown" v-bind:source="text">Application 6</vue-markdown>
	</div>
</div>