I'm getting the model from the view with this:
<script>
Module.getModel(#Html.Raw(Json.Encode(Model)))
</script>
Which calls this:
var getModel = function(model) {
vModel= model;
};
This works to initially get the model, but I need to update one of the model values via dialog ajax.
var loc = $("#Location").val();
$.ajax({
url: $("#root").attr("href") + "Home/SetLocation",
context: $(this),
type: 'POST',
data: { location: loc },
success: function() {
$(this).dialog("close");
reloadGrid();
},
error: function() {
alert("There was a problem updating your Location.");
}
});
The controller action saves the location to profile and redirects to "Index" action:
public ActionResult SetLocation(string location)
{
_dashboardTasks.SaveLocationToProfile(location);
return RedirectToAction("Index");
}
Which updates the model with the new profile information and returns it to the view:
public ActionResult Index(HomeViewModel homeViewModel)
{
SetUserLocation(homeViewModel);
return View(homeViewModel);
}
At this point the breakpoint on the first code block is hit again, but the function for it, getModel, is never called and the javascript model is never updated. So the success function which calls for the grid to reload, reuses the old data instead of the new data.
How can I update vModel with the value changed in the controller?
Do I have to add a declaration to the success function explicitly redefining the value?
success: function() {
$(this).dialog("close");
vModel.Location = loc;
reloadGrid();
},
This works, but I don't understand why the model is not being updated with the current code.
Related
I am trying to call a view with an ajax-Call, passing an Id to the Controller-method. The Id is passed, everything is fine until I call the view in the return-Statement. Nothing happens.
$("#btnCreatePackage").click(function () {
var workflowId = $("#workflowId")[0].value;
$.ajax({
url: '#Url.Action("Create", "package")',
type: 'get',
data: { id: workflowId },
success: function (data) {
return data;
},
timeout: 500
});
});
public ActionResult Create(int id) {
IList < Workflow > workflows = WorkflowService.GetWorkflowList();
ModifyPackageViewModel vm = new ModifyPackageViewModel
{
Package = null,
Workflow = workflows.SingleOrDefault(x => x.Id == id),
Workflows = workflows,
Hosts = ScalingService.GetHostList(),
SelectedHostNames = new List<string>(),
Factor = 1
};
if (!vm.SelectedHostNames.Any()) {
if (vm.Hosts.Any()) {
vm.SelectedHostNames.Add(vm.Hosts.First().Name);
}
}
return View(vm);
}
The curious thing is, if i#m calling the view via #Url.Action without passing the Id with the following code, it works.
<a href="#Url.Action("Create")">
<div class="submenu-item add">
neues paket anlegen
</div>
</a>
public ActionResult Create() {
IList<Workflow> workflows = WorkflowService.GetWorkflowList();
ModifyPackageViewModel vm = new ModifyPackageViewModel
{
Package = null,
Workflow = workflows.FirstOrDefault(),
Workflows = workflows,
Hosts = ScalingService.GetHostList(),
SelectedHostNames = new List<string>(),
Factor = 1
};
if (!vm.SelectedHostNames.Any()) {
if (vm.Hosts.Any())
{
vm.SelectedHostNames.Add(vm.Hosts.First().Name);
}
}
return View(vm);
}
In both cases the Controller-method is called, goes through to the end without errors, in the first case nothing happens, in the second case everything is fine.
Anyone any ideas??????
Thanks, daniel
You can't return the data from an ajax call. You can store it in a variable declared outside, or do something inside your success handler.
This works just as well with your success handler (success: function(data) ...). The main thing to remember is the scope of the data that is returned from your controller.
EX:
var outsideVariable; // You can store the data in here for later if you need to
$.ajax({
url: '#Url.Action("Create", "Package")',
type: 'GET',
data: { id: workflowId }
}).fail(function (data) {
// Fail handler
}).done(function (data) {
// Success, Do Something
YourFunctionThatProcessesData(data);
// Or store the data into a variable that has outside scope
outsideVariable = data;
}).always(function () {
//Do this no matter what
});
function YourFunctionThatProcessesData(data)
{
// do stuff with the data
}
At least I fixed it, I did not need an ajax-Call, instead I just used this:
$("#btnCreatePackage").click(function() {
var workflowId = $("#workflowId")[0].value;
window.location.href = '#Url.Action("Create", "package")/' + workflowId;
});
It can be that simple........
Question background:
I've implemented a search feature in the header of my MVC site. Its features a input text-box with a 'Search' Button.
The Issue:
Currently I have implemented a AJAX function in the shared master layout.cshtml view that handles the click event of the search button, as shown:
$(document).ready(function () {
$(".searchBtn").click(function () {
var $searchTerm = $("#searchInput").val();
$.ajax({
url: '#Url.Action("ProductSearch", "Product")',
type: 'POST',
data: {
"searchTerm": $searchTerm,
"pageNumber": 0
},
success: function (result) {
window.location.href = result.url;
},
failure: function () {
alert('failed');
}
});
});
});
This is the ProductSearch method of the the Product Controller the AJAX call. The search term along with the page number is sent to the controller method:
public ActionResult ProductSearch(string searchTerm, int pageNumber)
{
if (searchId == 0)
{
searchId = 1;
}
var productDetailHandler = new ProductPageDBHandler(
new ProductDetailSqlServerHandler(new ProductDetailDataSetConvertor()));
var searchList = productDetailHandler.ProductSearch(searchTerm);
return View(searchList.ToPagedList(pageNumber, 3));
}
The problem is that this seems to not be returning the view I've associated with the ProductSearch method. How do I go about correctly redirecting to thw correct view once the user has submitted their search query?
Your ajax function is calling a method that returns a view. Change you success callback to
success: function (result) {
$('#someElement').html(result);
},
This will replace the contents of <div id="someElement"></div> with the returned view.
I have a navigation bar that is pretty much the only piece of persistant template in my web application (in that is always there regardless of route).
In that navbar I show a Login link if the user is not logged in, and if they are I show their name, the problem I having is that I can't get the nav to keep it's state. The uses logins,
runLogin: function(e) {
e.preventDefault();
var element = $(e.currentTarget),
self = this;
$.when($.ajax({
url: 'http://app-api.dev/api/oauth/access_token?grant_type=password&client_id=1&client_secret=xyz',
method: 'POST',
data: element.serialize(),
dataType: 'json',
success: function(data) {
// Set the cookie, this will need to be sent in every singal request going foward.
$.cookie('access_token', data.access_token);
// So we have the access token we use this to populate our user details
},
error: function(response) {
// We can build a universal error view that would be quite and pretty easy to do.
}
})).done(function() {
$.ajax({
url: 'http://app-api.dev/api/users/me',
dataType: 'json',
method: 'GET',
success:function(user) {
self.model.set(user);
self.launchDashboard();
}
});
})
},
launchDashboard: function() {
localStorage.setItem('user', '');
localStorage.setItem('user', JSON.stringify(this.me));
App.Routes.Application.navigate('dashboard', { trigger: true } );
}
Basically I login, request my details from the API, and use those to set a model, the model I am setting has already been passed in to the navigation view, and has a change listener on it.
showUserDetails: function() {
this.loggedInUserMenu = new App.Views.navigationViewLoggedIn({
model : this.model
});
},
the above fires this,
App.Views.navigationViewLoggedIn = Backbone.View.extend({
el: '.navbar-right',
template: _.template( $('#tpl-navigation-logged-in').html() ),
events: {
},
initialize: function() {
this.render();
},
render: function() {
this.$('.li-login').replaceWith( this.template({
user: this.model.toJSON()
}));
}
});
Router
initialize: function() {
Pops.Models.AuthUser = new Pops.Models.User;
this.navigation_bar = new Pops.Views.navigationView({
model: Pops.Models.AuthUser
});
},
On successful login the loggedInNavigation is visisble, and I am at app-client.dev/#dashboard however if I navigate to `app-client.dev/#groups I lose the loggedInNavigation and it reverts back to just saying "login".
Why?
=== Edit I ahve attached the method that creates the main nav it is done on the initialize of the routes. The method that does the view update is all the in the previous code, login sets the model that is int he navigation view, listening for a change ===
Im using knockout with MVC. Im trying to pass an observable array of objects from knockout back to my MVC controller action for saving to the database. If I pass the Array from knockout over to my controller action via ko.toJSON(viewModel.ArrayName) it comes back as null in my controller parameter. If I try to pass it to MVC via ko.toJS(viewModel.ArrayName) it has the correct number of items but the data is null for some reason. Any help on how to do this would be greeatly appreciated. Thanks!
My JQuery Data Retrieval Method:
var dataService = {};
var viewModel;
$(document).ready(function () {
dataService.getAccessLevelList();
})
dataService.getAccessLevelList = function () {
$.post('/DataService/GetAccessLevelList', null, function (data) {
viewModel = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
});
}
This is the problem method:
updateAccessLevels = function () {
$.post('/DataService/UpdateAccessLevels', { accessLevels: ko.toJSON(viewModel.AccessLevels) }, function (status) {
alert(status);
});
}
My MVC Controller Data Retrieval action:
[HttpPost]
public ActionResult GetAccessLevelList()
{
FacilityAccessViewModel viewModel = new FacilityAccessViewModel();
viewModel.AccessLevels = unitOfWork.AccessLevelRepository.Get().ToList();
return Json(viewModel);
}
The parameter is coming back NULL or with NULL data when trying to pass it in from Knockout on this controller method.
[HttpPost]
public ActionResult UpdateAccessLevels(List<AccessLevel> accessLevels)
{
try
{
foreach (AccessLevel record in accessLevels)
{
unitOfWork.AccessLevelRepository.Update(record);
}
unitOfWork.Save();
return Json("SUCCESS");
}
catch (Exception ex)
{
return Json(ex.ToString());
}
}
Below is the JSON data shown via fiddler thats being posted to my MVC controller action when i pass in { accessLevels: ko.toJSON(viewModel.AccessLevels) } the controller parameter is coming in null using this
[{"Access":[],"Id":1,"AccessLevelDesc":"TEST222"},{"Access":[],"Id":2,"AccessLevelDesc":"TEST222"}]
Below is the JS data shown via fiddler thats being posted to my MVC controller action when i pass in { accessLevels: ko.toJS(viewModel.AccessLevels) }, in this case the list has two members as expected, but the data is all null in the properties
accessLevels[0][Id] 1
accessLevels[0][AccessLevelDesc] TEST222
accessLevels[1][Id] 2
accessLevels[1][AccessLevelDesc] TEST222
If I pass in a single object to my controller it works just fine, but I cant seem to figure out the proper way to post an array of objects to my controller from an obervablearray back to a POCO entity.
Try sending it as a JSON request by specifying the correct request Content-Type header:
updateAccessLevels = function () {
$.ajax({
url: '/DataService/UpdateAccessLevels',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(viewModel.AccessLevels),
success: function(status) {
alert(status);
}
});
};
I would like to have an infinite/endless scroll data rendering from a JSON feed. I am interested in accomplishing something similar to Pinterest or Google Reader using Backbone/Underscore/jQuery.
How do I apply the infiniScroll.js module to my backbone view? The goal is to fetch and append the next page's ("page" URL parameter) tweets when you scroll near the end of the page. Problem: when reaching the bottom of page, same JSON page feed is fetched. How to change the page parameter in the URL to be &page=2, etc.
Demo: http://dl.dropbox.com/u/19974044/test.html OR http://jsfiddle.net/k4rPP/3/
// Define the model
Tweet = Backbone.Model.extend();
// Define the collection
Tweets = Backbone.Collection.extend({
model: Tweet,
// Url to request when fetch() is called
url: 'https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&trim_user=false&count=10&screen_name=cnn&page=1&callback=?',
parse: function (response) {
return response;
},
// Overwrite the sync method to pass over the Same Origin Policy
sync: function (method, model, options) {
var that = this;
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: that.url,
processData: false
}, options);
return $.ajax(params);
}
});
// Define the View
TweetsView = Backbone.View.extend({
initialize: function () {
_.bindAll(this, 'render');
// create a collection
this.collection = new Tweets;
// Fetch the collection and call render() method
var that = this;
this.collection.fetch({
success: function () {
that.render();
}
});
// infiniScroll.js integration
this.infiniScroll = new Backbone.InfiniScroll(this.collection, {success: this.appendRender, param:'page', includePage:true});
},
// Use an extern template
template: _.template($('#tweetsTemplate').html()),
render: function () {
// Fill the html with the template and the collection
$(this.el).html(this.template({
tweets: this.collection.toJSON()
}));
}
});
var app = new TweetsView({
// define the el where the view will render
el: $('body')
});
The url attribute can be specified as a function rather than a string. So you could replace it with something like this:
...
currentPage: 0,
url: function() {
this.currentPage++;
return 'https://path.to.url/?page=' + this.currentPage;
},
...