update viewmodel in knockout and update the UI - c#

below is my javascript that loads the model and i binded it to a dropdown and a table to show data. which works and shows the data.
var _observableViewModel = null;
$(document).ready(function () {
var jsonModel = '#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model))';
_observableViewModel = ko.mapping.fromJSON(jsonModel);
ko.applyBindings(_observableViewModel);
});
once a user selects the an item from the dropdownlist i am calling a ajax function that returns jsonresult and want to update the viewmodel and update the table as well. i tried something below but no effect.
i am using mvc.
thanks for the help!
function GetData() {
$.getJSON("/Home/Test", function (data) {
ko.mapping.updateModel(data);
})

since you are already using ko.mapping you really should use the mapping overload specifying a target :
ko.mapping.fromJSON(jsonModel, {}, _observableViewModel)
It will update the observable as before, as well as calling the observable valueWillMutate / valueHasMutated methods to update the UI.

Related

How to pass mapped array to PageMethods?

I've been trying to pass a data array to c# web method with using jquery. I have a table which has selectable rows. And my function must pass the id's of selected data. But i can't pass the object array with PageMethods.
Here is my jquery function;
function DeleteQuestions()
{
var table = $('#questTable').DataTable();
var data = (table.rows('.selected').data()).map(function (d) { return d.q_id; });
PageMethods.Delete(data);
}
When i debug it with firebug, veriable data looks like : Object["543","544","546"] as i wanted.
And here is my Web Method:
[WebMethod]
public static void Delete(List<string> questId)
{
DB_UserControl carrier = new DB_UserControl(); //break pointed here
}//and looks it doesn't come here
It doesn't work, and the error is : Cannot serialize object with cyclic reference within child properties. I've searced for error but i couldn't figured it out. So need some help. Thanks in advance.
Note:Error throws at script function's last line: PageMethods.Delete(data);
And i think it might be about mapped data causes some kind of loop behavior.
Problem solved with changing syntax. I use
var data = $.map(table.rows('.selected').data(), function (d) {
return d.q_id;
});
instead of given line. I don't know what caused the error but this code works fine and i get data in c#. Thank you all

ASP.Net MVC Refresh Page without destroying ViewModel

I want to create a multilingual webpage. To switch between languages I've got a dropdown on my page. If the change event of the dropdown gets fired the Method called "ChangeLanguage" in my Controller is called.
public ViewModels.HomeViewModel HVM { get; private set; }
// GET: Home
public ActionResult Index()
{
this.HVM = new ViewModels.HomeViewModel();
return View(this.HVM);
}
public JsonResult ChangeLanguage(int id) {
return Json(new {Success = true});
}
Now I'd like to to change my "SelectedLanguage" Property in my ViewModel (HVM) - but the Reference is null. May anyone explain why HVM is null in my ChangeLanguage Method?
After my SelectedLanguage Property is changed I'd like to reload my whole page to display it's texts in another language
e.g.
#model ViewModels.HomeViewModel
<html>
<div class="HeaderText">
Text = #{
#Model.TextToDisplay.Where(o =>
o.Language.Equals(Model.SelectedLanguage)).First()
}
</div>
Here's what I want to do in PseudoCode:
PseudoCode:
public JsonResult ChangeLanguage(int id) {
this.HVM.SelectedLanguage =
this.HVM.AvailableLanguages.Where(o =>
o.ID.Equals(id)).First();
Page.Reload();
return Json(new {Success = true});
}
May anyone explain why HVM is null in my ChangeLanguage Method?
Adhering to stateless nature of HTTP protocol, all (unless explicitly added into request header) requests (MVC method calls) loose state data associated with it. Web server treats every request a new request and creates new instances of classes right from controller itself.
In your case since it is a new request, controller has a HVM property defined but in ChangeLanguage it is not instantiated (it gets instantiated only into Index method which is not called when you invoke ChangeLanguage) hence it is null.
After my SelectedLanguage Property is changed I'd like to reload my
whole page to display it's texts in another language.
Option 1: Refresh page
Simple option to implement. Pass the language selection to server, server will return a new view with specific data. Drawback, whole page will refresh.
Option 2: Update view selectively
If option 1 is really not acceptable, then consider this option. There are multiple ways you can achieve it. Basically it involves either (a) breaking you view into partial view and update only the portion that is affect by selection or (b) bind data element with a JS object.
(a) - Not much need to be said for this.
(b) - Data binding can easily be done if you employ a JS library like KnockoutJS.
Change your methods to these methods , This trick will work for you =>pass your model to Change language from view. Also update JsonResult to ActionResult.
public ActionResult ChangeLanguage(ViewModels.HomeViewModel model,int id)
{
this.HVM.SelectedLanguage =
this.HVM.AvailableLanguages.Where(o =>
o.ID.Equals(id)).First();
return RedirectToAction("Index",model);
}
public ActionResult Index(ViewModels.HomeViewModel model)
{
if(model == null)
{
this.HVM = new ViewModels.HomeViewModel();
}
return View(this.HVM);
}

Getting Hidden Values after $(window).load method in code behind

Context:
I converted HTML Select to Multiselect checkboxes on runtime. This required that I write my javascript code on the jquery event :
$(window).load(function () {
mulDC(); //this func converts loaded HTML select to ul with checkboxes
});
Now whatever user selects/checks on the run, I need those values back in my C# code behind.
What I have already tried is,
I created Hiddenfield and used it to populate it:
$('#<%=hdnDC.ClientID %>').val(arrSelectedValues);
This is returning me empty since this piece of code is inside .load method. I cannot use document.ready.
Need help here :)
UPDATE:
Function mulDC(). If code for .multiselect (external js file) is important, I can attach that too.
function mulDC() {
$('#chkDC').multiselect({
includeSelectAllOption: true,
renderInDiv: '#accDC',
showSelectedIn: '#selDC',
showSelectedValueIn: '#selDCVal',
chkBoxesID: 'chkDC'
});
getAllValueDC();
$('#chkDC li input:checkbox').on('change', function () {
getAllValueDC()
});
function getAllValueDC() {
var sThisVal = $('#chkDC :checkbox:checked').map(function () {
return this.value + ',';
}).get();
$('#<%=hdnDC.ClientID %>').val(sThisVal);
}
}

Running JavaScript in page from the backend (AJAX)?

I'm new to integrating JavaScript into a web site, but I'm going to need it often in my web site.
Here is an example:
Assuming I have the function:
showAlert()
Say I have:
<div id="some_div">
</div>
Could someone provide me some kind of example that would do this:
If I have a button and the user clicks it, this should raise an event in the backend and call some method in my C# file. Then my C# file should be able to call some other javascript method of the front end which would call showAlert() and display the alert in the div.
This is what I can't seem to find any information on.
The basic idea of passing information to and from the server. Any help with this would be really appreciated.
Thanks
Your best bet is to use a framework like jquery, then bind to the button, call the service, and handle the response. The below is a quick example of this.
$(document).ready(function()
$('#Button1').bind('click', function () {
// This grabs the page you are in so that you can call it correctly
var pagePath = window.location.pathname;
var testId = $("#some_div").val();
var url = pagePath + "/TestService";
$.post(url, { id: testId },
function (data) {
showAlert(data);
}
});
};
});
First, you need to make sure the document is ready at some point. Bind allows the the button to be bound when the document loads. Then, by clicking it, you execute the anonymous function that grabs the testId, calls your service, and handles the data response in a success callback.
Hope that gets you started in the right direction!
EDIT: Added backend webforms "service" exposure
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static string TestService(string id)
{
var string = DBCollection.FirstOrDefault(x => x.id == id); // Or whatever you want to return the data
return "You called me on " + DateTime.Now.ToString() + "with " + string;
}
}
This would allow you to call the "WebMethod exposed on your page. For more help with this, please see the following link.
http://www.tugberkugurlu.com/archive/asp-net-web-forms---calling-web-service-page-methods-using-jquery
EDIT: Additional Considerations when performing this type of approach in webforms.
Calling a webmethod with jquery in asp.net webforms

Dynamically search database and show results using Javascript and C#

I want to search a database for a clientName and dynamically show the results while the user is typing so they can select a User. It is now my understanding that this cannot be done without using javascript.
So if the user is typing "Al" then reults of clients called "Allan, Alison, Ali..." etc would show in a dropdownlist like display under it.
At the moment the user is entering the Clients name into a Textbox.
I know that creating the DropDownList should be done something like this:
private void InitializeNameDropDown(DataTable dtTable)
{
string ClientName = Clienttb.Text;
MySqlDataReader Reader = MySQLQuery(ClientName);
int nTotalRecords = dtTable.Rows.Count;
for (int i = 0; i < nTotalRecords; i++)
{
NameDropDown.Items.Add(dtTable.Rows[i]["Client"].ToString());
}
}
MySQLQuery() just checks that the client exists within the database.
But I don't know how to dynamically interact with the database to return the results as the user is typing.
Any Help will be appreciated, Thank you in advance.
You can do it without JS, hang event on text change on TextBox (OnTextChanged), and in there update DDL ( dont forget to set AutoPostBack=true ).
But it can easily make user wait ( "freeze page" ), or even rollback what he wrote if you are using Ajax.NET
I strongly recommend using JS rather then this ( use JS and WCF/ashx/regular WS, any of these will do ) due to performance gain and much better possibilities of customization.
ASP anyway generates a load of JS for "ASP controls".
This can be applied for example http://www.codeproject.com/KB/aspnet/Cross_Domain_Call.aspx
You'll have to hook into the keyup event on the text box and fire an XmlHttpRequest from that event - if you're using jQuery it's pretty simple:
$('#mytextbox').keyup(function() { $.ajax(blah blah) });
Alternatively, as Dennis says, just use the auto-complete plugin - it's very simple and works well.
As for the client side try jquery and jqueryui's autocomplete, it's just a suggestion, jquery has a nice ajax call and it's really simple to use, and for the jqueryui autocomplete, you just pass it keywords and it will create a list right under the input box.
http://jquery.com/
http://jqueryui.com/
http://api.jquery.com/jQuery.ajax/
Here's some code that might get you going.
It uses the jquery Javascript library. It assumes you're getting the full HTML of the results list that you want to display to the user. You'll need more Javascript to dynamically show/hide the box that contains the list. You'll also need a server-side script that gets a collection of search results based on some search text. That script should be located at the URL defined in the #searchPartialUrl tag (which can be hidden). The search text should be in an input called #searchText.
I like this method because you can maintain your JS code in a separate file and reuse it. Your server just needs to create HTML views that have all the async target information in regular HTML tags.
I also implemented a delay between checking key-events so that you're not constantly sending requests to your server. (I got this method from another answer on stackoverflow, but I can't seem to find it now. I'll give credit when I do.)
// This function is used to delay the async request of search results
// so we're not constantly sending requests.
var mydelay = (function() {
var timer = 0;
return function(callback, ms) {
clearTimeout(timer);
timer = setTimeout(callback, ms);
};
})();
var asyncSearchForm = function(onSuccess) {
var keyupWrapper = function(keyCode) {
// if this key was an arrow key, then
// ignore the press
for (var i = 37; i <= 40; i++)
if (keyCode == i)
return;
// get all the search info from the form
var searchText = $('#searchText').val();
var searchPartialUrl = $('#searchPartialUrl').val();
// make the ajax call
$.ajax({
type: "POST",
url: searchPartialUrl,
data: {
searchText: searchText
},
dataType: "html",
// on success, the entire results content should be replaced
// by the results returned
success: function(data, textStatus, jqXHR) {
$('#searchResults').html(data);
onSuccess();
},
// on error, replace the results with an error message
error: function(jqXHR, textStatus, errorThrown) {
$('#searchResults').html('<p>An error occurred while getting the search results.</p>');
}
});
};
onSuccess = (typeof (onSuccess) == 'undefined') ? function() { } : onSuccess;
// On each key-up event, we'll search for the given input. This event
// will only get triggered according to the delay given, so it isn't
// called constantly (which wouldn't be a good idea).
$('#searchText').keyup(function(e) {
// delay between each event
mydelay(function() {
// call key up
keyupWrapper(e.keyCode);
}, 500);
});
}
Update:
You said you're using C#. If you're using MVC, you'll need an action in your controller to be a target for your async request. Here's an example:
[HttpPost]
public ActionResult GetSearchResults(string searchText)
{
// Here, you should query your database for results based
// on the given search text. Then, you can create a view
// using those results and send it back to the client.
var model = GetSearchResultsModel(searchText);
return View(model);
}

Categories