Setting Breeze Navigation Property in Knockout subscription - javascript

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.

Related

Wicket - Append Javascript (What is Better Practice?)

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" ) );
...
}

Pass generic type as type parameter

I am struggling to come up with a solution to a problem i'm facing, where i am trying to use a generic type as a type parameter.
I have the following two classes/types:
UserModel.ts:
export class UserModel{
private _id : string;
public get id() : string {
return this._id;
}
public set id(v : string) {
this._id = v;
}
....
}
HttpResponse.ts:
export class HttpResponse<T>{
private _success : boolean;
public get success() : boolean {
return this._success;
}
public set success(v : boolean) {
this._success = v;
}
private _model : T;
public get model() : T {
return this._model;
}
public set model(v : T) {
this._model = v;
}
}
As you can guess, I am using this to have a generic type to handle http calls easily. The intended use is to call my http method with the HttpResponse type and whatever the expect result type is as the type parameter. For example, when making a user related http call the type parameter would be HttpResponse<UserModel>> or for a resource related call it would be HttpResponse<ResourceModel>>. However, i don't seem to be having any luck when trying this.
In my data service I have a method that POSTS to the server called 'create' and
create<T>(data: any){
//Angular's HttpClient
return this.http.post<T>(data, ...);
}
I then have a service that extends this class and overloads the create method with some extra bits before it calls super.create. I run into the issue at this point because I want to pass in HttpResponse<Type the service should return> which in the following case would be HttpResponse<UserModel>:
create<HttpResponse<UserModel>>(user: UserModel){
//stuff happens here
return super.create<HttpResponse<UserModel>>(user, ...);
}
However, this returns a syntax error at create<HttpResponse<UserModel>>.
I had a look online and found another way to achieve this as something along the lines of:
create<HttpResponse, UserModel>(user: any){
//stuff happens here
return super.create<HttpResponse<UserModel>>(user, ...);
}
But, again, this returns an error stating "HttpResponse is not generic".
The design idea is that by passing in the types in this manner, the json response from the server can be automatically mapped into the appropriate type, making it simple to use the response throughout the application
Any pointers as to where I am going wrong in my design?
A subclass has to maintain the entire interface of its base class (with some exceptions that aren't relevant here). If your data service base class contains a create method that is generic and works for every T, then your subclass cannot override create with a method that only works for T = HttpResponse<UserModel>. Instead, consider (1) defining a new method with a different name or (2) moving the T parameter from the create method to the base class itself, so that when your subclass extends the base class, it can specify the single T that it works with. (Compare to this recent question.) If this doesn't seem to be what you're looking for, then please provide more information.

C# property name change effects ID in HTML

c# code:
public class Person{
public string Name { get; set; }
public age int { get; set; }
}
cshtml code which generates an id of #Person_Name
#Html.DropDownListFor(m => m.Person.Name)
javascript code:
$('#Person_Name').on("change", function () {
//Do something
}
If I change the Person class property name from Name to FullName. The next step is to modify the cshtml code to read as:
#Html.DropDownListFor(m => m.Person.FullName)
I understand you can manually go in and change the Jquery code, but if this change is made and the person making the change is unaware of the jquery, it is going to cause an error. Is there a way to prevent this from happening through some form of notification or logging? Rather than just remembering that the jquery needs to be changed.
You do have the option to use:
#Html.IdFor(x => x.Person.FullName)
Or
#Html.NameFor(x => x.Person.FullName)
That does rely on having small bits of script in pages, but for what id do this is mostly calling functions in .js resources which from my point of view I find better for reuse anyway.
You may still not get alerted to all issues unless you choose to compile your MVC views, you'll probably get a warning if you have the view open. How you set up your project to compile your MVC views will depend on the type of project but a quick Google should help with that one.

Invoke Javascript in WPF webbrowser without dispatcher

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
}
}

mvc 3 update model

I have a view that displays several checkbox lists of items in tables (the lists are dynamic). I need to know how to update the ViewModel when the user clicks on a checkbox so that when control returns to the controller it can inspect the viewmodel to determine which items were selected.
The VM contains several properties such as
public IEnumerable<IFilterItem> Cities;
public Interface IFilterItem
{
int ID { get; set; }
string Name { get; set; }
bool IsSelected { get; set; }
}
What I need help with is how to set the view's copy of the model data in the checkbox's onclick handler. Thanks as always, you guys are great!
Are you using the CheckBoxFor helper? If so, when control returns to the controller your view model should just have IsSelected set based on the state of the checkbox.

Categories

Resources