I have an MVC app where I am getting a XML file and loading into an object.
In my view I have several client/server operations and since MVC is stateless I stored the object into a MemoryCache (to prevent the constant loading of the XML file). While this seems to work nicely, however my concern is how to remove this MemoryChache item when I am done?
If the user goes to different view then I want to remove this object.
However I don't know what event I could use to ensure this object gets removed.
It appears that I can handle it with JQuery:
$(window).unload(function () {
// Server call to clear MemoryCache
});
Related
I've got a page where a DataTemplate is being used to bind to the model for that content, e.g.:
<DataTemplate x:DataType="models:MyDataType">
... content ...
</DataTemplate>
In that content, I need to be able to bind a Click event. I need that click event to exist in the view model that is set as the page's DataContext:
<Page.DataContext>
<vm:MyViewModel x:Name="ViewModel">
</Page.DataContext>
but I'm really struggling with getting it to compile. Every approach I try results in the compilation error "Object reference not set to an instance of an object".
I know I can't use x:Bind because that will bind to the DataTemplate's DataContext, so I've been trying to use Binding and, based on other SO answers I've read, it seems like the answer should be:
Click="{Binding DataContext.Button_Click, ElementName=Page}"
where Page is defined as the x:Name for the Page. I've tried removing DataContext. I've tried adding ViewModel.
What am I misunderstanding? Is it not possible to do what I want to do? I've tried using code-behind instead but I'm using Template 10 and that pushes almost everything onto the view model, which makes it harder for me to access things like the navigation service from code-behind.
tl;dr; use Messaging.
#justinXL is right, 'ElementName' can work. But is it best?
The problem you are trying to solve has already been solved with messaging. Most MVVM implementations include a messaging solution. Prism uses PubSubEvents; MVVM Light has its own messenger. There are others, too.
The idea is that an outside class, typically described as a message aggregator, is responsible for statelessly receiving and multicasting messages. This means you need to have a reference to the aggregator but not a reference to the sender. It’s beautiful.
For example
A common use case might be a mail client and how the data template of a message in the list would include a trash/delete button. When you click that button, what should be called? With messaging, you handle the button_press in the model and send/publish a message (one that passes the item).
The hosting view-model has subscribed to the aggregator and is listening for a specific message, the Delete message that we just sent. Upon receipt, it removes it from the list and begins the process to delete it from cache/database, or whatever – including prompting the user with “Are you sure?”
This means all your data binding in your data template is local, and does NOT extend outside its local scope. Why does this matter? Because if you use Element Binding to reach the hosting page, it means you cannot 1) move this template to a resource dictionary or 2) reuse this template.
There are two other reasons.
you cannot use compiled x:Bind to do this because it already limits use of this painful binding approach – this matters because a data template is typically in a list, and performance should always be prioritized, and
It adds considerable complexity.
Complexity?
I am a big fan of sophisticated solutions. I think they are rare and are the trademark of truly smart developers. I love looking at such code/solutions. Complex is not the same as sophisticated. When it comes to complexity, I am not a fan. Data binding is already difficult to wrap your head around; multi-sourcing your data binding across scope boundaries is pure complexity.
That’s what I think.
Your binding expression is correct, except it won't work with a Button_Click event handler. You will need an ICommand defined in your page's ViewModel.
Since you are using Template10, you should be able to create a DelegateCommand called ClickCommand like this
private DelegateCommand<MyDataType> _clickCommand;
public DelegateCommand<MyDataType> ClickCommand
{
get
{
_clickCommand = _clickCommand ?? new DelegateCommand<<MyDataType>>((model) =>
{
// put your logic here.
});
return _clickCommand;
}
}
And the binding will be updated to
<Button Command="{Binding DataContext.ClickCommand, ElementName=Page}" CommandParameter="{x:Bind}" />
Note I have also added a CommandParameter binding to the button as you might want to know which MyDataType instance is associated with the clicked button.
I'm playing around with ASP.NET MVC 4, but I have some problems with understanding. For better explanation I will use a simple "synthetic" situation.
Let's say I have model Person with 2 properties:
string Name
PersonType Type (e.g. Student, Employee, Military...)
Let's say in my controller I have private property Person. I can initialize this object in Index method, pass into View and build html page. Ok.
Now when user updates one of fields of person instance at the client side (he can input a new person name or select new person type using dropdown list), I want to update my model immediately. So, my general question is How can I achieve it?
Obvious solution for me: I can send an ajax request to controller from JS with new data. I thought that I can call controller's method UpdateName(string name) and update manually property Name with new data. BUT my person instance is NULL inside of this method! My second question is Why I can't access to initilized model object from other method? I think it's all about my bad understanding of client server interaction.
The final case of my situation: when user click's on the button "Save" I want to save created person into file on the server side, but I don't want to use any forms and receive all needed data just after clicking this button (because in my real task I can't use forms and also I can't receive all needed fields from html page after button clicking).
I have found the dirty solution. In JS I created another class Person with same properties. Now I can update instance of this class when I want and pass json data to server for saving it.
Is there any better solutions?
Its not that dirty to have javascript objects to represent your model. In fact thats how I do it. I use KnockoutJS to give me a client side model - which is essentially the MVVM pattern.
You are trying to use the MVC model in a way which you can't. However, the Knockout model you can use how you wish. You basically have a javascript representation of your server side model and once you are done with it you send it to the server.
In order for your server side methods to pick up your client side model you simply have to ensure the post request contains the data and as long as properties names are the same in the parameters of the method they will match themselves.
Why I can't access to initilized model object from other method?
Because it's not initialized anymore. Don't use the controller class to store persistent data across requests. The controller object is disposed after a request completes and then re-initialized on a new request. So anything that one action methods saves at the class level is gone when you get to another action method. Each request from the client to the server should be considered a fully isolated event, independent of any previous requests.
When you want to save your model, what you would do in that action is re-fetch it from the database, apply the changes, and save it back to the database.
but I don't want to use any forms
I'm not really sure what you mean here. Do you mean you want to use AJAX instead of POSTing the page directly? If so, that's fine. There are probably a number of tools out there to help you, personally I often just create a form anyway but instead of a submit button I have a plain button and add some JavaScript code (using jQuery) to serialize the form and perform an AJAX POST.
As long as the keys for the POST values map to your model fields in the same way they would in an out-of-the-box form, then your action method will still be able to receive the proper model type. On the server-side it doesn't matter if it's from an AJAX call or a normal POST. The difference, however, is that the response for an AJAX call should probably be in JSON format instead of responding with a view.
So instead of this:
return View(someModel);
You might have something like this:
return Json(someModel);
I am using Infragistics(Ignite UI) controls in my ASP.NET MVC3 application.
I have grid which I've bound to 'Customer' data. Works fine.
Now I have button. On clicking I make an ajax call.
In the controller I write query which selects only a part of 'Customer' data.
I return the data using json.
I try to re-bind it using:
$("#CustomerGrid").igGrid("dataSourceObject", returnData);
But the grid continues to show old data. It doesn't refresh.
Call the data bind method like so:
$("#CustomerGrid").igGrid("dataSourceObject", returnData);
$("#CustomerGrid").igGrid("dataBind");
or even like so:
$("#CustomerGrid").igGrid("dataSourceObject", returnData).igGrid("dataBind");
Just a general note - changing the data source can be extra overhead and generally not ideal solution. If I understand correctly you are replacing it with a part of the original collection? If the collection is big and/or you need to reset back to original state - perhaps consider simply returning id-s to the ajax call and use the Filtering feature?
In an MVC4 project, I have a form that contains a partial view which is an index view of languages studied at school. It is a default type view template index, with Add, Delete, Edit links per row etc. When you Add or Edit, it opens an Add or Edit view for a Language. After e.g. adding a language, the updated partial view is returned.
My problem is that if the user opens the Language form, edits and captures on the main form will be lost. I can't just do an Ajax save before opening the Language form, as the main form may only be partially complete and fail validation. What I am thinking of doing though is using an AjaxPreserve action that takes a FormCollection, and stores it in session (o on disk, or anywhere) and therefore no model binding and server validation is performed.
I then have two problems: I will need to disable client validation before calling the AJAX action, and I will need to repopulate the main form using the FormCollection I saved earlier. I think there should surly be some jQuery voodoo to disable client validation, but I am completely stumped on repopulating the form.
ALTERNATE SOLUTION: Instead of using 'sub-forms', I can use editor templates, in pop-ip forms, where the FK IDs are not required, but that us only in certain cases, so my question still stands.
Could you use something like Knockout where you create javascript model and bind it to a grid/dialog edit/template view. I would transform the whole data to a JS model, bind it to a table/grid and then track all changes on the client side. When all is done, just serialize the whole model back to the server and update the data store.
If this is an acceptable scenario, it will save you a lot of trouble.
Familiarity with Knockout is required, but if you've used it before, you will be able to solve this in a very clean and efficient way.
This example on the Knockout website gives an idea of what I'm trying to suggest. Editing, deleting, adding is done on the client side until you send all of the data back to the server. You will need to track flags for each object to know if it's added, edited or deleted.
http://knockoutjs.com/examples/contactsEditor.html
Simple make the sub request for adding language using Ajax and repopulate the dropdown or what ever way you are accepting language on the main form on sucessfully save.
*This will save a lot of effort. *
Why don't you just use javascript?
E.g. You have main form, that stores some data. And when you need to add something specific like languages you open popup using partial view, allow user to fill form, but when user press submit you intercept action with js, save stuff to javascript array/object or whatever else and maybe store it in a hidden field of main form - for final submit
var newData = new Object();
newData.Field1 = $("#yourField1");
...
lanuageData.push(newData);
$("#languageContainer").val(JSON.stringify(languageData));
...
DataAnnotation validation works here as well like:
$.validator.unobtrusive.parse("your_partial_view_container");
When you need to edit some object that was already added to js array - open popup and fill it up with element of you js array. So basically you do all CRUD on client-side, saving changes only on final submit.
To make your code in a conrolller more clear you can use custom model binder which deserialize some string field from JSon to List or any other kind of object -> so it can be validated on server side.
Would saving your values to local storage be acceptable? What about using TempData?
Our problem is a very basic, simple implementation of editing the database using JSF + EJB.
Keeping things short:
two separate XHTML views, use two separate Managed Beans #RequestScope.
WebuserListBean and EditWebuserBean, and with #ManagedProperty we inject WebuserListBean, so we could obtain selected user data. So far no problems. Views are filled with data succesfully!
BUT!
We want to be able to edit the user!
And here (to my surprise) we cannot overcome the problem.
1st try:
Because the request scoped bean is dead after filling the view, on Save() method the #PostConstruct tries to launch again, of course it can't. So we couldn't even obtain it from database or anything.
2nd try:
Because the request scoped bean is dead after filling the view, if we do not set up user as field in #postconstruct, we lose our connection with user object which was linked on previous view (and injected, but now that view is dead too).
3rd try:
Cannot inject RequestScope in ViewScoped
Ok and our restrictions, because we think it's wrong way:
We dont want to create a SessionScoped Managed Bean for this
We dont want to use any params etc. We want to use EJB
We are not sure if we could store data in Stateful session bean which is our
endpoint for the module? Is it proper approach?
Thanks for any advice, we could paste some code but i guess it is pointless!
Cheers!
There are many ways to do it, but I recommend using the flash if the pages involved in the navigation are in the same folder (I recently found out reading a BalusC answer that there is a known issue with the flash, in which it will not hold values when navigating between pages in different folders!).
The flash is a way to hold parameters for a little longer than the context of a single request (concept taken from Ruby if I'm not mistaken, someone correct me if I'm wrong), allowing for the sent parameters to be fetched in a subsequent view, for example. Those values are discarded in the second request issued after saving them, if I'm not mistaken. You can inject the flash in your managed beans like this:
#ManagedProperty("#{flash}")
private Flash flash;
public void setFlash(Flash newFlash) {
flash = newFlash;
}
Then, you access it like a map with the put and get methods. If you use the put method in a bean, return a redirection rule and, on the second bean, use the get method your object should be there.
You can also find a highly comprehensible guide of communication in JSF (listing a really extensive list of options) here, in particular if you need to navigate between pages in different folders.