multiple knockout bindings and sharing them - asp.net-mvc-3

So I have a scenario where I am have knockout binding on my main page.
Index.cshtml:
<div data-bind="foreach breadcrumbs">
<div>
<script>
var IndexViewModel = function () {
var self = this;
self.breadcrumbs = ko.observableArray();
};
ko.applyBindings(IndexViewModel);
</script>
And a Partial View that loads inside the Index.cshtml. The partial view has its own knockout bindings:
<div id="someId">
</div>
<script>
var PartialViewModel = function () {
var self = this;
self.someFunction = function(){
// Access Breadcrumbs here
};
};
ko.applyBindings(PartialViewModel, "someId");
</script>
I want to access the breadcrumbs observableArray from the second partial view and add items to them. I am not even sure if this possible. Please help. I am also using sammy.js but for this purpose its not that relevant.

I don't like having to have dependencies between view models, so I've previously used a jQuery pubsub plugin to allow view models to talk to each other in a decoupled manner. You can see an example of it in this answer
Basically, when you update the breadcrumb, call publish with the new array, and the other view model would subscribe to that event.

An easy solution (but not very clean one) would be to store the indexViewModel in a global variable.
Index.cshtml:
var IndexViewModel = function () {
var self = this;
self.breadcrumbs = ko.observableArray();
};
// we create a global variable here
window.indexViewModel = new IndexViewModel();
ko.applyBindings(window.indexViewModel);
And then you can access this indexViewModel from your partial view model:
var PartialViewModel = function () {
var self = this;
self.someFunction = function(){
// Access Breadcrumbs here
// better use some wrapping functions
// instead of accessing the array directly
window.indexViewModel.breadcrumbs.push({});
};
};
ko.applyBindings(new PartialViewModel(), "someId");
</script>

Related

Knockout.js AJAX Get

I am new to using Knockout.js and for that matter JavaScript as well. I went through their tutorials and tried to modify the example to load data from server as below. Can anyone please point what's wrong with my code
JavaScript:
jQuery(document).ready(function () {
MyViewModel = function()
{
var self =this;
self.name = ko.observable("");
self.getJson = function()
{
jQuery.ajax({
//Do all the work
success: function(data)
{
self.name = data.name;
}
});
}
}
myViewModelObj = new MyViewModel();
ko.applyBindings(myViewModelObj);
myViewModelObj.getJson();
});
View:
<h1 data-bind="text: name "></h1>
After you have declare an object to be an observable, it then becomes a native function to knockout. In order to update the value, use
self.name(data.name);
Otherwise you are overwriting the function.

Pass value from view to Ajax

Lest say I got a view with this loop:
#foreach (var item in Model.Blogposts)
{
#item.Id
#Html.JQueryUI().Datepicker("Date")
}
So I got an Id and also a date choosen from the datePicker. Can someone show me how I can pass these two values to an Ajax that the loads a method?
$(".setDate").click(function () {
})
.load("/Home/Method?id=" + $(this).data("#itemID"));
});
Am I on the right way with what i´ve done so far? Help appreciated. Thanks!
EDIT:
Here is the method to which I want to pass the values:
public ActionResult SetDate(string valuefromDatePicker, string itemId)
{
//Code that updates the Time-property
//This I can figure out
return RedirectToAction("Test");
}
Which should mean that the view should look something like this:
#Html.JQueryUI().Datepicker("Date", new { data_url = Url.Action("SetDate", "Home", new { id = item.Id }) })
Should I also add a submit-button and give it the class .setDate?
You seem to be using some custom #Html.JQueryUI().Datepicker extension method that is not part of ASP.NET MVC. You should have at least mentioned the custom library you are using. In general most of the jQuery UI helper methods have overloads with an htmlAttributes parameter. This would allow you to add custom data-* attributes that you could use in your javascript code later. Consult the documentation of the library you are using about how to specify custom HTML attributes but your code might look something along the lines of:
#foreach (var item in Model.Blogposts)
{
#item.Id
#Html.JQueryUI().Datepicker("Date", new { data_url = Url.Action("Method", "Controller", new { id = item.Id }) })
}
and then in your javascript file:
$('.setDate').click(function () {
var url = $(this).data('url');
$('#result').load(url);
});

how to load a partial view ona selector using jquery?

var uri="#Url.Content("/Views/Shared/_LogOnPartial")";
$("#logindisplay").load(uri);
it give me error
Files with leading underscores ("_") cannot be served.
why the url don't work.
You can use following code to load Partial Views in ~/Views/Shared/ Folder.
<script type="text/javascript">
$(document).ready(function () {
$("#btnclick").click(function () {
var uri = '#Url.Content("_LogOnPartial")';
$("#logindisplay").load(uri);
});
});
</script>
HTML is,
<input type="button" id="btnclick" value="Load View" />
<div id="logindisplay">
</div>
You should use
"#Html.Partial("/Views/Shared/_LogOnPartial)
to load partial instead of #Url.Content("/Views/Shared/_LogOnPartial")
best practice is to define path for partials, Layouts & views earlier
in App_Start/RouteConfig write method like below
public static void RegisterViewEngines(ICollection engines)
{
/*
* {0} = view name
* {1} = controller name
*/
engines.Clear();
engines.Add(new RazorViewEngine
{
ViewLocationFormats = new[] { "~/Views/{0}.cshtml" },
MasterLocationFormats = new[] { "~/Views/Shared/{0}.cshtml" },
PartialViewLocationFormats = new[] { "~/Views/Partial/{0}.cshtml" }
});
}
then execute it in Globa.asax like
RouteConfig.RegisterViewEngines(ViewEngines.Engines);
then you can easily call partial like this
#Html.Partial("_LogOnPartial");

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?
My main page has a DropDownList (DropDownListFor) and a partial view which ONLY contains a list of "items". The items shown in this partial view are dependent upon the item selected in the DropDownList. There's a 1 to many relationship between the DropDownList item and the items in the partial view. So, when the user changes the value of the DropDownList, the content in the partial view will dynamically change to reflect the item selected in the DropDownList.
Here's my DropDownList:
<div data-role="fieldcontain">
Choose Capsule:<br />
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules" })
<br />
</div>
Here's my Partial View declaration on the same page:
<div data-role="fieldcontain">
#Html.Partial("_FillerPartial", Model.Fillers)
</div>
I'm not very familiar with Ajax, but looking at other examples, here's what I have for my Ajax:
$(document).ready(function () {
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
alert("server returned: " + data);
}
});
});
});
And finally, here's a screenshot of what's going on. By changing the "Choose Capsule" drop down list, I want the Filler list to update dynamically:
You can load the drop down list as a partial view from the controller using ajax.
The controller code:
[HttpGet]
public virtual ActionResult GetFillersByCapsule(string cappk)
{
var model = //Method to get capsules by pk, this returns a ViewModel that is used to render the filtered list.
return PartialView("PartialViewName", model);
}
The main view html:
<div id="filteredList">
</div >
The partial view
#model IEnumerable<MyCapsuleModel>
foreach (var x in Model)
{
//Render the appropriate filtered list html.
}
And you can load the filtered list using ajax:
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
$("#filteredList").empty();
$("#filteredList").html(data);
}
});
});
Hope this helps.
You can't update the partial, per se, because the partial will never be rendered again without a page reload. Once you receive the HTML, ASP is done, you're on your own at that point.
What you can do, of course, is switch out the content of a particular div or whatever using JavaScript. Your example in particular screams Knockout, so that's what I would recommend using.
Change your HTML to add a data-bind to your containing div:
<div data-role="fieldcontain" data-bind="foreach: filler">
<button data-bind="text: name"></button>
</div>
And your DropDownList:
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules", data_bind = "event: { change: updateFillers }" })
Then, some JavaScript:
var FillersViewModel = function () {
var self = this;
self.fillers = ko.observableArray([]);
self.updateFillers = function () {
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
self.fillers(data.fillers) // where `fillers` is an array
}
});
}
}
var viewModel = new FillersViewModel();
ko.applyBindings(viewModel);
This is a very simplistic example, and you'll need to do some more work to make it do everything you need it to do in your scenario, but the general idea is that every time the dropdown list is changed, Knockout will call your updateFillers method, which will execute the AJAX and put new data into the fillers observable array. Knockout automatically tracks changes to this array (hence the "observable" part), so an update is automatically triggered to any part of your page that relies on it. In this scenario, that's your div containing the buttons. The foreach binding will repeat the HTML inside for each member of the array. I've used a simple button element here just to illustrate, but you would include the full HTML required to create your particular button like interface. The text binding will drop the content of name in between the opening and closing tag. Refer to: http://knockoutjs.com/documentation/introduction.html for all the binding options you have.
There's much more you could do with this. You could implement templates instead of hard-coding your HTML to be repeated in the foreach. And, you can use your partial view to control the HTML for this template. The important part is that Knockout takes the pain out of generating all this repeating HTML for you, which is why I recommend using it.
Hope that's enough to get you started.

How does the view in backbone marionette know which model is associated with it?

https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.view.md
In this example:
<script id="my-template" type="text/html">
I think that <%= showMessage() %>
</script>
MyView = Backbone.Marionette.ItemView.extend({
template: "#my-template",
templateHelpers: {
showMessage: function(){
return this.name + " is the coolest!"
}
}
});
model = new Backbone.Model({name: "Backbone.Marionette"});
view = new MyView();
view.render(); //=> "I think that Backbone.Marionette is the coolest!";
I've tried analyzing this code and based on my understanding of Backbone, you have to specify which model the view is associated with. I tried understanding Marionette views and I don't know which part of the docs or in this example shows how the view knew that this refers to the newly created model. Or is this just a typo?
There's an error in that example. It should show this:
model = new Backbone.Model({name: "Backbone.Marionette"});
view = new MyView({
model: model
});
view.render(); //=> "I think that Backbone.Marionette is the coolest!";
I'll update the docs to fix this

Resources