I have a primary form defined and nicely laid out, it does what it needs to do...
#{ Html.BeginForm(); }
#Html.ValidationSummary(false)
#Html.AntiForgeryToken()
#Html.EditorFor(model => model)
<h2>Properties</h2>
<hr />
#* I want to put some stuff here... *#
<br class="space" />
<div class="clearfix">>
<button type="submit" data-bind="click: save">
Save
</button>
</div>
#{ Html.EndForm(); }
Now, then. This model (or ViewModel, rather) has an IList<PropertyViewModel> attached to it.
A PropertyViewModel has its own set of validations. They are pretty simple for now, but there is a chance that later there will be more complicated uses for this setup.
I am using KnockoutJS for my viewModel consistency. Though I suppose it is fairly irrelevent. I want to display a second form in a jQuery UI Dialog and return the result, essentially..
<script type="text/javascript">
var viewModel = {
name: ko.observable(),
description: ko.observable(),
properties: ko.observableArray(),
save: function () {
alert(ko.toJSON(viewModel));
},
includeProperty: function () {
$("#dialog").dialog({
width: 500,
closeText: '',
resizable: true,
buttons: {
'Submit': function () {
$(this).dialog('close');
callback( #* I want the new data to get sent back *# );
},
'Cancel': function () {
$(this).dialog('close');
return false;
}
}
});
}
};
function callback(value) {
alert(ko.toJSON(value)); // (I will push the new property to the viewmodel here)
}
ko.applyBindings(viewModel);
</script>
However, I am not really sure how to actually put the EditorTemplate into the dialog, moreover I am not sure how to get the data back out of it.
I don't completely understand your question, but from what I understood what you are trying to do is pass data to the dialog and retrieve data from the dialog. If that is the case then this may be useful:
http://api.jquery.com/jQuery.data/
Here is detailed example on how to use:
Passing data to a jQuery UI Dialog
Related
My viewModel has an array called 'Items'. I want to display the contents of 'Items' using a foreach binding. Everything works fine when I use regular HTML. But does not work with a dialogue box which I created using jQueryUI.
HTML:
<div id="skus0">
<div id="skus1">
<ul data-bind="foreach: Items">
<li data-bind="text:Name"></li>
</ul>
</div>
<input type="button" id="openQryItems" class="btn btn-info" value="Open" data-bind="click:openQueryItems" />
</div>
JavaScript:
// my view model
var viewModel = {
Items: [{Name:'Soap'},{Name:'Toothpaste'}]
};
// JS to configure dialogue
$("#skus1").dialog({
autoOpen: false,
width: 500,
modal: true,
buttons: {
"OK": function () {
$(this).dialog("close");
},
"Cancel": function () {
$(this).dialog("close");
}
}
});
// for mapping my model using ko.mapping plugin
var zub = zub || {};
zub.initModel = function (model) {
zub.cycleCountModel = ko.mapping.fromJS(model);
zub.cycleCountModel.openQueryItems = function () {
$("#skus1").dialog("open");
}
ko.applyBindings(zub.cycleCountModel, $("#skus0")[0]);
}
zub.initModel(viewModel);
I have created a fiddle here my fiddle
$.fn.dialog removes the element from its place in the DOM and places it in a new container; this is how it can create a floating window. The problem with this happening is that it breaks data binding, since the dialog DOM is no-longer nested within the top-level data-bound DOM.
Moving the dialog initialization to after ko.applyBindings will enable dialog to yank stuff out of the DOM after the list is populated. Of course, this means that after that point, future changes will still not be reflected, which may be important if you're wanting the opened dialog to change automatically.
If you are wanting the dialog contents to be fully dynamic, you could create a binding handler; we did this in our project. Here's a rough outline of how we did this:
ko.bindingHandlers.dialog = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingCtx) {
var bindingValues = valueAccessor();
var hasAppliedBindings = false;
var elem = $(element);
var options = {
id: ko.utils.unwrapObservable(bindingValues.id),
title: ko.utils.unwrapObservable(bindingValues.title),
// etc...
onOpen: function () {
if (!hasAppliedBindings) {
hasAppliedBindings = true;
var childCtx = bindingCtx.createChildContext(viewModel);
ko.applyBindingsToDescendants(childCtx, element);
}
}
};
elem.dialog(options);
}
return { controlsDescendantBindings: true };
}
...which we used like this:
<div data-bind="dialog: { title: 'some title', id: 'foo', ... }">
<!-- dialog contents -->
</div>
What return { controlsDescendantBindings: true } does is makes sure that outer bindings do not affect anything using the dialog binding handler. Then we create our own Knockout binding "island" after it is pulled out of the DOM, based on the original view model.
Although in our project we also used hybrid jQuery+Knockout, I would highly recommend you avoid this whenever possible. There were so many hacks we had to employ to sustain this type of application. The very best thing you should do is prefer Knockout binding handlers (and I think it has a "component" concept now which I haven't played with) over DOM manipulations to avoid buggy UI management.
I need some guidance/suggestions for an optimal way to save the order of a sortable list that takes advantage of Meteor.
The following is a scaled down version of what I'm trying to do. The application is a simple todo list. The end goal for the user is to sort their list where the data is picked up from the database. As the user sorts tasks, I would like to save the order of the tasks.
I've implemented this application without Meteor using php/ajax calls using sortable's update event that would delete the entry in the database and replace it with what was currently in the DOM. I'm curious to know if there are a better ways to do this taking advantage of Meteor's capabilities.
The following sample code is straight off of a live demo.
HTML:
<template name="todo_list">
<div class="todo_list sortable">
{{#each task}}
<div class="task">
<h1>{{title}}</h1>
{{description}}
</div>
{{/each}}
</div>
</template>
JS(Without the Meteor.isServer that simply populates the database.):
if (Meteor.isClient) {
//Populate the template
Template.todo_list.task = function () {
return Tasks.find({});
};
//Add sortable functionality
Template.todo_list.rendered = function () {
$( ".sortable" ).sortable();
$( ".sortable" ).disableSelection();
};
}
Sample data (Output of Tasks.find({})):
[{
title:"CSC209",
description:"Assignment 3"
},
{
title:"Laundry",
description:"Whites"
},
{
title:"Clean",
description:"Bathroom"
}]
You'd probably want to first sort your items by a new field on you collection then, you'll want to hook into the jQuery sortable update event:
if (Meteor.isClient) {
// Populate the template
Template.todo_list.task = function () {
return Tasks.find({}, { sort: ['order'] });
};
// Add sortable functionality
Template.todo_list.rendered = function () {
$('.sortable').sortable({
update: function (event, ui) {
// save your new list order based on the `data-id`.
// when you save the items, make sure it updates their
// order based on their index in the list.
some_magic_ordering_function()
}
});
$( ".sortable" ).disableSelection();
};
}
You template would look a bit like this:
<template name="todo_list">
<div class="todo_list sortable">
{{#each task}}
<div class="task" data-id="{{_id}}">
<h1>{{title}}</h1>
{{description}}
</div>
{{/each}}
</div>
</template>
And when that event is triggered, it would determine the order of the list and save the new order in the documents for the collection.
This isn't really a complete answer, but hopefully it helps a bit.
I want to return a partial view in Jquery Dailog and wanted to pass the viewmodel object to particular controller action, how to do that?
View
#Html.DropDownListFor(model => model.SelectedCountry, new SelectList(Model.CountryList, "CountryCode", "CountryName"), "---SELECT COUNTRY---",
new { #class = "chosen", #onchange = "this.form.action='/Home/Index'; this.form.submit(); " })
<input type="button" id="button1" value="Push"/>
<div id="dialog" title="Report" style="overflow: hidden;"></div>
Js
<script type="text/javascript">
$(function () {
$('#dialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
title: 'Report',
modal: true,
open: function() {
//here how to pass viewmodel
$(this).load("#Url.Action("CreatePartial")");
},
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
$('#button1').click(function () {
$('#dialog').dialog('open');
});
});
Controller
public ActionResult CreatePartial(HomeViewModel homeViewModel)
{
return PartialView("_CreatePartial", homeViewModel);
}
Currently, "homeViewModel.SelectedCountry" is Null, how to pass model in Jquery?
If you're using AJAX, you should not use HTTP GET to pass model to server. Instead use HTTP POST (as in $().ajax({method: 'POST'}) and pass data as POST data ($().ajax({method: 'POST', data: #Html.Raw(Json.Encode(Model))}))
You convert the model into an JSON object by using the the build-in JSON-helper, just modify your request to:
$(this).load('#Url.Action("CreatePartial")',#Html.Raw(Json.Encode(Model)));
#Html.Raw is needed to prevent HTML-Encoding.
I tested it and it worked.
I have an asp.net mvc app, using JQuery UI dialog. I'm trying to submit form data to the controler action method. I do hit the action method but my object has no data. Do you know why?
From Filter.cshtml
$("#selectUnits").dialog({
autoOpen: false,
title: 'Select Units',
width: 400,
modal: true,
minHeight: 200,
buttons: {
"Cancel": function () {
$(this).dialog("close");
},
"Submit": function () {
$.post('/Data/SetUnitNumbers', $("#frmSelectedUnits").submit(), function (data) {
alert('This worked');
});
}
} // END OF BUTTONS
}); //END OF DIALOG
From Controler...Action Method:
public void SetUnitNumbers(object data)
{
int a = 5;
}
From SelectUnits.cshtml where form 'frmSelectedUnits' lives. Essentially it is a bunch of checkboxes values that I'm trying to send back to the server:
<body>
<form id="frmSelectedUnits" action="/" >
<div id="unitNumberCheckboxes" style=" ">
<div>
#Html.CheckBox("SelectAllUnitNumbers", false)<label for="SelectAllUnitNumbers"><b>Select/Unselect All Units</b></label>
</div>
<div id="unitCheckboxes">
#foreach (var item in Model)
{
<div style="float:left">
#Html.CheckBox("UnitNumbers", false)<label for="UnitNumbers">#item.unit_number.ToString().PadLeft(3, '0') </label>
</div>
}
</div>
</div>
</form>
</body>
jQuery .post is:
$.post(url, data, success-callback-function);
where data is A map or string that is sent to the server with the request.
Calling $("#frmSelectedUnits").submit() probably won't work.
Try:
$.post('/Data/SetUnitNumbers', $("#frmSelectedUnits").serialize(), function (data) {
alert('This worked');
});
jQuery docs on .serialize()
I was experimenting with jQuery UI and MVC3 and I stumbled upon the following issue:
I have very basic page that uses AJAX
<%: Ajax.ActionLink("Edit", "Edit", new { id = 1 }, new AjaxOptions() { UpdateTargetId = "dialog", OnSuccess = "DisplayPopup" }, null)%>
<div id="dialog" title="Location">
</div>
This is the controller code:
public ActionResult Edit(int id)
{
return PartialView();
}
[HttpPost]
public ActionResult Edit()
{
return Content("Saved!");
}
and partial view edit:
<b>whatever</b>
<% using (Ajax.BeginForm("Edit", "Home",
new AjaxOptions()
{
UpdateTargetId = "editForm",
HttpMethod = "POST"
}))
{%>
<div id="editForm">
<input type="submit" value="Save" />
</div>
<% } %>
the code above works fine.
now I add the jquery UI popup code:
<script type="text/javascript">
function DisplayPopup() {
$('#dialog').dialog('open');
}
$('#dialog').dialog({
autoOpen: false,
width: 600,
modal: true,
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
</script>
after that in Firefox and Chrome it works fine, whereas in IE8 I see the following issue:
click edit - makes AJAX call to Edit(int id) action and shows the edit view inside a popup
click save - makes AJAX call to Edit() and shows the text "Saved!"
close the popup
click edit - AJAX call to Edit(int id) - again
click save - this time it makes FULL postback (only in IE)
any ideas?
Thanks!
Try this seeing it works the first time but not the second. Create the dialog new every time and destroy it when you are done.
<script type="text/javascript">
function DisplayPopup() {
$('#dialog').dialog({
autoOpen: true,
width: 600,
modal: true,
buttons: {
"Close": function () {
$(this).dialog("close");
}
}, close: function() {
$(this).dialog("destroy");
}
});
}
</script>
I had the same trouble: worked in FF, but not in IE8.
Try adding something to the partial view response.
I was having this same trouble in IE and ended up adding #ViewBag.Message to the partial view response, where ViewBag.Message = "Submitted " + DateTime.Now.ToLongTimeString(); was assigned in the controller on Post.
This suddenly and surprisingly caused the partial view to render in the correct target element instead of loading the view as a new page in IE8.