I have two panels in Wicket.
ParentPanel and
ChildPanel
Scenario
ChildPanel is a component of ParentPanel.
Every time a certain event is fired in the Parent panel, I want to prepend a certain javascript in the ChildPanel.
Working Solution
ParentPanel.java
public class ParentPanel extends Panel
{
private static final long serialVersionUID = 4306746527837380863L;
private final ChildPanel childPanel;
public ParentPanel(String aId, IModel<AnnotatorState> aModel)
{
super(aId);
model = aModel;
// initially the Child panel is empty. passing empty model
childPanel = new ChildPanel("child-container", Model.of());
childPanel.setOutputMarkupId(true);
add(childPanel);
}
#OnEvent
public void onClickText(RenderEvent aEvent)
{
LOG.trace("Event Fired");
IPartialPageRequestHandler iPartialPageRequestHandler = aEvent.getRequestHandler();
Integer someData = getSomeData();
childPanel.setDefaultModel(Model.of(someData));
//I am trying to add the child panel to the ajax target to ensure rerendering of child panel.
iPartialPageRequestHandler.add(childPanel);
}
}
ChildPanel.java
public class ChildPanel extends Panel
{
private static final long serialVersionUID = -3849226240909011148L;
private static final Logger LOG = LoggerFactory.getLogger(ChildPanel.class);
private IModel<Integer> model;
public ChildPanel(String aId, IModel<Integer> aModel)
{
super(aId);
model = (aModel);
}
#Override
public void renderHead(IHeaderResponse aResponse)
{
super.renderHead(aResponse);
model = (IModel<Integer>) getDefaultModel();
if (model == null)
return;
Integer someData = model.getObject();
String someJavascript = createSomeJavascript(someData);
log.debug("Rendering Updated UI with the JS: ", javascript);
aResponse.render(OnDomReadyHeaderItem.forScript(javascript));
}
}
Apparently renderHead() is called every time the childPanel is added to the iPartialPageRequestHandler and it does my work that is to update the UI on every event fired in the ParentPanel.
Problem
However I have been told that this is not a good practice. Since in this case, the JS is added to renderHead(), then it ends up in the page source code - that gets cumbersome when sending (large) JSON data. A good place to attach the JS to the AJAX target needs to be found (maybe render() or probable better onRender() or onAfterRender()) only if its possible/doable in Wicket. Due to my limited knowledge, I am not able to guess how else I can implement the scenario. Any other (better or possible) solution is welcomes and appreciable.
Thanks.
I assume the problem is that the createSomeJavascript creates a big chuck of code?
I would then refactor it so that createSomeJavascript just calls a function that you add to the Component using a JavaScriptResourceReference. This way, only a small bit of Javascript ends up in the source.
For example, put your javascript in an external file like this:
private static final ResourceReference JS_QM = new JavaScriptResourceReference( ClientPanel.class, "question.mark.js" );
#Override
public void renderHead( Component component, IHeaderResponse response )
{
super.renderHead( component, response );
response.render( JavaScriptReferenceHeaderItem.forReference( JS_QM, "question-mark" ) );
...
}
Related
Using DI in components works great with inject (#inject or in Codebehind with [inject]).
Now how does it work if you want to use DI in a normal class? I found exactly the same question here:
Blazor - Call JavaScript from C# class
Unfortunately, although the question is marked as answered, it is not clear how this is actually supposed to work. I'll summarize it here:
you create a class which should be used as DI, here for example for JSInterop (e.g. to use JavaScript outside from components):
public class JsInteropForClasses
{
private readonly IJSRuntime jSRuntime;
public JsInteropForClasses(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
public async void MessageBox()
{
await jSRuntime.InvokeVoidAsync("MessageBox", "DI question!!!");
}
}
you register service in Program.cs
builder.Services.AddTransient<JsInteropForClasses>();
and now comes the crucial question, how do you use this in a other class that is not a component (so where you can't use inject)?
I applied the suggested solution, but I get argument problem because constructor of DI-class expects an object type IJSRuntime and I don't pass anything during creation:
JsInteropForClasses js = new JsInteropForClasses();
js.MessageBox();
Therefore, I can't use DI (because program can't start).
The following variant does not work either:
JsInteropForClasses js;
js.MessageBox();
I searched for a long time, but only found this one entry (see link). All others refer to DI and components.
Does anyone know about how to use DI in own class (not components)?
Thanks
When you register a service in the DI container (in Program.cs) initialization of the service will be handled by the DI. That means you should NOT call the constructor on your own. The only thing you need to do is to register the service (with the interface if necessary) properly. Like this:
builder.Services.AddTransient<JsInteropForClasses>();
or
builder.Services.AddTransient<IJsInteropForClasses, JsInteropForClasses>();
Then you can inject the service (or interface of the service) in the class constructor you want to use.
Like:
public class SomeClass {
private readonly JsInteropForClasses jsInteropForClasses;
public SomeClass(JsInteropForClasses jsInteropForClasses) {
this.jsInteropForClasses = jsInteropForClasses;
}
}
or in Razor as shown by Henk here
#inject JsInteropForClasses ij
Here is what I want to achieve:
I have a (normal) class in a Blazor WASM project. I want to invoke a JavaScript function from my class.
If I want to do this from a Razor component it is working fine, I inject IJSruntime and invokevoidasync to my JavaScript.
But it goes wrong when I try to do it from a class.
First I tried to inject it like this:
[Inject]
IJSRuntime JSRuntime { get; set; }
But ended up with error message: Value cannot be null. (Parameter 'jsRuntime')
I learned from this post that I have to "Inject it in the traditonal way", so I did this:
public class InvokeJavaScript
{
private readonly IJSRuntime jSRuntime;
public InvokeJavaScript(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
public async void InvokeMyJs()
{
await jSRuntime.InvokeVoidAsync("giveMeAMessage");
}
}
But from there on I am stuck, I know that this must be some key .NET knowledge but I am missing a piece here.. I want to call the "InvokeMyJs" methode like:
InvokeJavaScript ij = new InvokeJavaScript();
ij.InvokeMyJs();
But know I am facing an error: There is no argument given that corresponds to the required formal parameter 'jSRuntime' of 'InvokeJavaScript.InvokeJavaScript(IJSRuntime)'
That I get the error makes sense to me but I dont know how to fix it, what parameter must I send to InvokeJavaScript(IJSRuntime jSRuntime) and how do I do it correctly? Can anyone give an example?
When you use DI you have to follow it through.
In general that means avoiding new, as in:
InvokeJavaScript ij = new InvokeJavaScript(); // no parameter
register the InvokeJavaScript as a Service in Startup.
inject it where you need it.
Program.cs
builder.Services.AddTransient<InvokeJavaScript>();
SomeComponent.razor
#inject InvokeJavaScript ij
What is the meaning of R.layout.activity_main ?
I understand that "." operator is used to define variables of a particular object but in this case its been used twice so I can't make anything out of it. Also what exactly is "R" and "layout"?
I mean obviously they are classes (right?) but what is their function ? Basically explain R.layout.activity_main !
Please comment if question too vague or too broad.
R.java is a class (with inner classes, like layout or string) generated during the build process with references to your app's resources. Every resource you create (or which is provided by Android) is referenced by an integer in R, called a resource id.
R.layout.* references any layout resource you have created, usually in /res/layout. So if you created an activity layout called activity_main.xml, you can then use the reference in R.layout.activity_main to access it. Many built-in functionality readily accepts such a resource id, for example setContentView(int layoutResid) which you use during the creation of your activity and where you probably encountered this particular example.
If you create a string resource (in strings.xml) like this:
<string name="app_name">Application name</string>
it will get a new reference in R.string.app_name. You can then use this everywhere where a string resource is accepted, for example the android:label for your application in AndroidManifest.xml, or on a TextView; either in the xml:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
/>
or in code: textview.setText(R.string.app_name).
You can access resources programmatically using the Resources class, to which you can get a reference by calling getResources on any context (like your activity). So for example you can get your app name described above in your activity by calling this.getResources().getString(R.string.app_name).
You can also supply different resources for different device properties/settings (like screen size or language), which you can access using the same references in R. The easiest example here, imho, is strings: if you add a new values folder in /res with a language specifier (so /res/values-nl for Dutch) and you add strings with the same identifier but a different translation and the resource management system cleverly figures out which one to provide for you based on your user's device.
I hope this helps a bit. For more information on resources see the documentation.
R is an auto-generated class, and describe the resources of your project. It contains static inner classes. layout is one of them. R.layout refers to the inner class called layout. activity_main is a public static final member of the class layout
In Android R is an Java-class that is auto-generated from your resources by the build process.
The R.layout member is a auto-generated class that contains all IDs for layouts.
R.layout.activity_main is a static final int member that represents the ID of the layout-file in layout/activity_main.xml.
Okay, so R is a generated class. If you're lucky enough you'll never see it nor have to touch it, otherwise you did something very wrong.
When you make a layout, or any change to a layout, Android Studio generates quite a couple files for you. This includes a R.java file. Here's a piece of an R.java class:
public final class R {
public static final class anim {
public static final int abc_fade_in = 0x7f050000;
public static final int abc_fade_out = 0x7f050001;
public static final int abc_grow_fade_in_from_bottom = 0x7f050002;
public static final int abc_popup_enter = 0x7f050003;
public static final int abc_popup_exit = 0x7f050004;
public static final int abc_shrink_fade_out_from_bottom = 0x7f050005;
public static final int abc_slide_in_bottom = 0x7f050006;
public static final int abc_slide_in_top = 0x7f050007;
public static final int abc_slide_out_bottom = 0x7f050008;
public static final int abc_slide_out_top = 0x7f050009;
}
public static final class attr {
public static final int actionBarDivider = 0x7f010062;
public static final int actionBarItemBackground = 0x7f010063;
public static final int actionBarPopupTheme = 0x7f01005c;
public static final int actionBarSize = 0x7f010061;
public static final int actionBarSplitStyle = 0x7f01005e;
public static final int actionBarStyle = 0x7f01005d;
public static final int actionBarTabBarStyle = 0x7f010058;
public static final int actionBarTabStyle = 0x7f010057;
public static final int actionBarTabTextStyle = 0x7f010059;
As you can see, in this case if I'd type
R.anim.abc_fade_in
I'd be selecting the value 0x7f050000;.
Every layout file is mapped out in this R file, and gets an ID by which android recognizes it. The layouts are located in R.Layout. So, R.layout.activity_main gets you the value of variable activity_main of the class layout of the class R.
And again, don't try finding or changing your generated R file. Things can go very wrong if you do that.
From https://stackoverflow.com/a/4953282/1393766
R is a class containing the definitions for all resources of a particular application package. It is in the namespace of the application package.
If you want to inflate a layout inside your activity class,you can use R.layout.activity_main where layout specifies that your resource is a layout and it's name is activity_main.
If you want to use a drawable image in a layout inside your activity class,you can use R.drawable.image_name where drawable specifies that your resource is a drawable image.
Also,R.java class is an autogenerated class which is not supposed to alter manually.
I have an application implementing the WPF WebBrowser control. It loads a page containing some JS functions that have to be called from my application, possibly from other threads. Preferrably, I would like to stick to the MVVM pattern and keep the code for parsing the function return in the model. Calling the InvokeScript method on the WebBrowser object should happen on the Dispatcher thread (and thus in the view), since it is a UI element.
The steps I currently take to get this job done is (roughly in pseudo):
- subscribe to the LoadCompleted event of the browser (view)
- set the browser source (model -> viewmodel -> view)
- catch the LoadCompleted event (view -> viewmodel -> model)
- some logic (model)
- invoke script (model -> viewmodel -> view)
- get script result (view -> viewmodel -> model)
- some logic (model)
This results in quite some back-and-forth communication between the model and the view (through the viewmodel). Since I am not that experienced with WPF (or MVVM in that matter), I am wondering whether there is a neater way of accomplishing this task (and by neater I mean: less calls and events between the model, viewmodel and view).
I know this is not exactly the answer to your question, but it might help you even more in the future. Take a look at the component called CefSharp. That's a c# wrapper around Chrome Embedded Framework. It is very MVVM friendly, it is open source, free and it's reasonably easy to develop for. I've recently moved to it from another Chrome wrapper (Awesomium) and very happy with it.
CefSharp allows you to call js functions from the page and it even supports async/await for those calls.
So main point of MVVM is to separate interface (which is platform specific: windows\android\ios\windows phone etc etc) from everything else, so that you could reuse logic (viewmodel\model) on different platforms. So it's clear you cannot call InvokeScript directly from viewmodel - but not because of dispatcher. Dispatcher you can abstract out (for example), since in some cases you need it in your view model. So usually when viewmodel needs to perform operation on view - events (or just delegates) are used:
public class MyViewModel
{
public Func<string, object> InvokeScript { get; set; }
public Func<string, Task<object>> InvokeScriptAsync { get; set; }
public async void Something() {
var result = await InvokeScriptAsync("my script");
// do something
}
}
And in your view:
public class MyView {
private void OnViewModelChanged(MyViewModel vm) {
vm.InvokeScript = text => Dispatcher.Invoke(() => browser.InvokeScript(text));
vm.InvokeScriptAsync = text => browser.InvokeScriptAsync(text); // for example
}
}
I am building a SPA (Single Page Application) using Breezejs and Knockoutjs.
I am running into an issue when trying to set a navigation property inside a knockout subscription. On the final line of the ko.subscription the console.log function shows me the entity, however, the WebPresences navigation property is null.
Not sure if the fact its in a ko.subscription really matters but I've been able to set the navigation prop just in a js function I call right before save, so I think it has some significance.
So here is my Entity Model
public partial class Entity
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> WebId { get; set; }
public virtual WebPresence WebPresence { get; set; }
}
And here is my ko.subscription and relevant variables:
var vm = {
newEntity: ko.observable(datacontext.createBreezeEntity('Entity')),
newWebPresence: ko.observable(datacontext.newBreezeEntity('WebPresence')),
}
vm.newEntity().WebPresence.subscribe(
function (data) {
var self = this;
if (data === null)
self.target(vm.newWebPresence());
console.log(vm.newEntity());
}
);
And last but not least my datacontext
createBreezeEntity: function (entityName) {
return manager.createEntity(entityName);
},
newBreezeEntity: function (entityName) {
return manager.metadataStore.getEntityType(entityName).createEntity();
}
I do not understand what you're striving to accomplish.
One thing I'm pretty confident about ... is that your the datacontext.newBreezeEntity creates an object that is just hanging in thin air and isn't part of any navigation property.
Let's look at your datacontext.newBreezeEntity method:
return manager.metadataStore.getEntityType(entityName).createEntity();
This indeed does create a new entity of the type named entityName. But this is a 'proto-entity'. It does not belong to an EntityManager ... certainly not to the manager instance. It isn't related to any particular other entity (e.g., your mysteriously-named Entity entity). It's just a detached entity.
I'm betting you thought that it would belong to manager because you started the expression there. Well it doesn't. You lost the connection with manager the moment you asked for its metadataStore.
But there is so much else that makes no sense to me at all. I can't tell why you're subscribing to vm.newBreezeEntity nor why it's called "newBreezeEntity" nor what it's relationship is supposed to be to vm.newEntity nor what you think this is within the subscription function.
Perhaps you should step back and describe what you WANT this code to do.