How to use GWTP for a ListView (Widget)? - gwtp

I started to use GWTP for my project and I'm currently re-writing all my code to let it work with this library.
However, I struggle to understand how I use GWTP if I want e.g. a ListView with ListItemView items.
#Inject
public ToolsPresenter(PlaceManager placeManager, EventBus eventBus, MyView view, MyProxy proxy) {
super(eventBus, view, proxy, AdminToolPresenter.SLOT_AdminToolMainContent);
this.placeManager = placeManager;
ToolListView toolListView = new ToolListView(...)
ToolListPresenter toolListPresenter = new ToolListPresenter(....);
this.setInSlot(SLOT_ToolList, toolListPresenter);
}
What I want is to place my ListView inside a slot. I am very certain that I can't do what is shown up there but I just don't get how I use just simple Widgets with GWTP.
Or am I doing this completely wrong and I should just extend a Composite for ListView and not use GWTP stuff here at all?

There is a lot of information missing from your question so this is a difficult one to answer.
Assumption 1 - Your GWTP artifacts (ToolListView, ToolListPresenter, ToolListView.ui.xml, and ToolListModule) are setup correctly and ToolListModule is installed in a parent module.
Assumption 2 - You are using GWTP version 1.5+ which has typed slots.
You should not be instantiating your ToolListView or ToolListPresenter.
Simply add:
#Inject ToolListPresenter toolListPresenter;
If you are trying to call the setInSlot method then
Make sure ToolListPresenter is a PresenterWidget
Make sure your slot is not a NestedSlot.
Finally try moving the call to setInSlot outside of your constructor and into the overridden onBind() method.

Related

Create a View Component template/container that accepts HTML or other components as parameters

I have searched many places and have not seen anything similar to what I am thinking.
Let's say I want to create a reusable container component, like a card, form, or a modal, and save that as a View Component. How would I add a new view components inside of the "body" of that main View Component in a way that would make it maximally reusable?
The syntax here is just to demonstrate the idea of course, but for example, something like this:
<vc:parent var1="x" var2="y">
<vc:child var3="a" var4="b"></vc:child>
<vc:child var3="c" var4="d"></vc:child>
</vc:parent>
Is anything like this possible?
This doesn't necessarily need to use View Components—maybe partial views?—so long as the primary goal of reusing the containers of other reusable elements is achieved.
I have looked into helpers, but they are no longer available in ASP.NET Core.
So I figured out how to do it.
I used part of this tutorial about helpers: Templates With Razor
And modified it so it works with ViewComponents.
So to get it working, in a minimal example, create a ViewComponent class as such:
[ViewComponent(Name = "Test")]
public class VCTest : ViewComponent
{
public IViewComponentResult Invoke(Func<dynamic, object> Content)
{
return View(Content);
}
}
Create the actual template that you want, in a cshtml file like this:
#model Func<dynamic, object>
<div id="SomeTemplateTest">
#Model(null)
</div>
In this very simple case I just used the Func as model since there is only one parameter, but for more parameters you'd just have to call #Model.funname(null) instead of just #Model(null). No big deal.
when calling this component from your view, create your child elements beforehand like so:
#{Func<dynamic, object> children=
#<div>
<vc:child var1="a" var2="b"></vc:child>
<vc:child var1="c" var2="d"></vc:child>
<vc:child var1="e" var2="f"></vc:child>
</div>;}
The div is there only to encapsulate all the elements. I haven't found a way around that but it has no major implications.
Then call the parent ViewComponent tag passing on the parameters accordingly:
<vc:test content="children"></vc:form-test>
And that's it, worked perfectly. It is unfortunate that I could not find a more seamless way. But this does the job.
If anyone knows of a better alternative I'd love to know more.

Aurelia routing to the same moduleID

Hi there I have asked this on Gitter, but hope that someone here may be able to help.
I have two different routes that have the same moduleId. I have also set up a setting object within the routes with some data to differentiate what gets rendered. Everything works fine when I navigate to one of these routes from somewhere else, but if I navigate from one to the other neither the constructor or the activate are fired. am i missing something??
I had this problem and it took me a while to find a solution - this should help you I hope;
You need to add the determineActivationStrategy() method into your class, and then return as below.
import {activationStrategy} from "aurelia-router";
export class ExampleViewModel {
determineActivationStrategy() {
return activationStrategy.replace;
}
}
This will force the VM to be replaced when you're routing to it from itself.
Here's some more info on the different Activation Strategy types;
activationStrategy.no-change – reuse instance with no lifecycle events
activationStrategy.invokeLifecycle – call lifecycle methods on the ViewModel instance each time the route switches
activationStrategy.replace – construct new instance of ViewModel and invoke full lifecycle on it
Taken from here ZombieCodeKill - Aurelia Routing Beyond the Basics
Found the answer here :) Although not a complete fix out of the box, the implementation is possible

Aurelia dynamic composition

I am trying to implement dynamic composition in aurelia. More precisely I am creating tabs and for each new tab I am adding a new div and inside I am using compositionEngine.compose(...) to add the component corresponding to that tab. A working example can be found here: https://gist.run/?id=08a04dad8d94af01989d789a216195f3 . I am experiencing however some strange behaviour. For instance if I open the same component twice in 2 tabs it seems to reuse (share) the viewModel. Just open module 2 once, click change to increment the counter then open it again. It will show the previous value. Any ideas?
You could mark your view models with the transient decorator
import {transient} from 'aurelia-framework'
#transient()
export class M2 {
cnt = 1;
click(event){
this.cnt = this.cnt + 1;
}
}
Thank you James, you are right, in the mean time I understood the cause of my problem. The compositionEngine calls container.get(...) which of course returns a singleton of each class by default. Adding #transient() as you said makes the container return a new instance. What I still do not understand is how (where) does aurelia creates the model instance for other cases. I assume if the containers are indeed a tree that the model has to be registered using registerInstance in the child container (created after container.createChild())

Is it possible to HIDE Javascript Object's prototype! What's the MYSTERY behind this?

I'm using openui5. There is a constructor Function for UI control Button,unable to see the prototype properties of the Button but the same thing when executed in browser console, shows up!
sap.m.Button.prototype.Move = function(){
console.log('Move');
}
var oButton = new sap.m.Button({text:"Hello"});
oButton.Move(); // throws undefined function!
The same code when executed browser in console, it works!
jsbin --> http://jsbin.com/tepum/1/edit
After running the code I find that creating the first instance of sap.m.Button causes script to change the prototype of sap.m.Button. It's valid in JavaScript but not very smart if you ask me.
A first creation causes a synchronous request (no no as well) to fetch library-parameters.json.
If you run the code the second time it will have prototype.move because creating an instance of Button will not change the Button.prototype.
The capital M in Move would suggest a constructor function so I would advice changing it to lower case.
Since fetching the parameters is synchronous you can create the first instance and then set the prototype:
console.log("First Button creation changes Button.prototype");
var oButton = new sap.m.Button({text:"Hello"});
sap.m.Button.prototype.move = function(){
console.log('Move');
}
oButton.placeAt('content');
oButton.move(); // logs Move
My guess is that this is done to lazy load controls, if a Button is never created then the json config files are never loaded for these unused controls. It has a couple of drawbacks though.
You have to create an instance first before you can set the prototype.
The config files are synchronously loaded so when creating first instance of many controls with a slow connection would cause the app to be unresponsive.
A better way would be for a factory function to return a promise so you create the control the same way every time and the config files can be fetched asynchronously.
[update]
Looking at the config it seems to be config for the whole gui library so I can't see any reason why this is loaded only after creating a first instance. A library that changes it's object definitions when creating instances is not very easy to extend because it's unpredictable. If it only changes prototype on first creation then it should be fine but it looks like the makers of the library didn't want people to extend it or they would not make the object definition unpredictable. If there is an api documentation available then maybe try to check that.
[update]
It seems the "correct" way to extend controls is to use extend.
#HMR is right the correct way to extend a control is by using the extend function provided by UI5 managed objects, see http://jsbin.com/linob/1/edit
in the example below when debugging as mentoned by others you will notice that the control is lazy loaded when required, any changes you make prior are lost when loaded
jQuery.sap.declare("my.Button");
jQuery.sap.require("sap.m.Button");
sap.m.Button.extend("my.Button", {
renderer: {}
});
my.Button.prototype.Move = function() {
console.log('Move');
};
var oButton = new my.Button({
text: "Hello"
});
oButton.placeAt('content');
oButton.Move();
It's not hiding the prototype per se. If a constructor function exits normally then you get that function's prototype. But, if a constructor function actually returns some other object then you get that other object's prototype, so it's not valid to assume that just because you added to the Button prototype that when you call new Button() that you will see your method on whatever you get back. I'm sure if you de-obfuscate that code you'll find that the constructor you are calling has a "return new SomeOtherInstanceOfButton()" or similar at the end of it.
Edit: Ok it's a bit difficult to see what's really going on in that sap code but, it looks like they have code that overwrites the prototypes of controls to add features to them, such as: sap.ui.core.EnabledPropagator, and those things aren't run until you actually instantiate a button. So if you change your code to instantiate the button on the page, then add to it's prototype, then construct and call the method, it works fine. Like so:
http://jsbin.com/benajuko/2/edit
So I guess my answer is, when you run it from console it's finished mucking around with that prototype, whereas in your test you were adding to the prototype, then constructing the button for the first time (which changes the prototype again) then trying to call your old one, which is no longer there.

How to use DI with WinRT

In a WinRT Page how can I inject dependencies?
I am thinking of doing something like this:
/// <summary>
/// A page that displays an overview of a single group, including a preview of the items
/// within the group.
/// </summary>
public sealed partial class MyPage : NSyncApplication.WinRT.Common.LayoutAwarePage
{
IMyDependency _myDependency;
public MyPage(IMyDependency myDependency)
{
_myDependency = myDependency;
this.InitializeComponent();
}
.
.
.
}
If this isn't a good practice please explain and recommend an alternative solution.
Note:
I don't need the specific DI containers that can be used with WinRT, that's been answered already and any idiot can look at nuget gallery and pick their choice.
This question is about how I can plug into the Page factory and inject my own dependencies. I have also looked at Prism for WinRT and that thing is even more convoluted than I remember the WPF version to be.
To repeat:
How can I inject into the page directly. Is there a page factory
or something that I can tap into to add custom instantiation code?
Should I inject to the code behind and make it a viewmodel? The Prism MVVM example had
another layer of abstraction for the ViewModel separate from the
code behind (which's considered part of the View). This is nice and cool, but requires more wiring and
custom mark ups than I care to do for my relatively simple project. I am hoping to roll with something more "light-weight". But may be there's an argument to be made against that, please explain.
Please, check MVVM-Light. They use VMLocator which exposes view models to which XAML can bind. On MSDN Magazine you can find an example of how to use it.