knockout sammy.js navigation issue - asp.net-mvc-3

I have a scenario like this.
Initially loaded when page is navigated to #Action.
Once the select action is performed data-bind="with tag is loaded"
User click on "Do Something" action is performed. Which replaces the whole "parentNode"
Now When the user clicks back, and the sammy.js notices the hash tag #Action/:id, I need to load the #Action to get back the main View and then select the id to load the data-bind="with" tag again.
How can I do this?
Currently the page does go back to "Action/:id" but since main view is not loaded it doesn't do anything. I have used "this.redirect("#Action") then selected the node, but the doesn't work.
<div id="parentNode">
<ul data-bind="foreach: items">
<li data-bind="click: $root.selectItem">
<h2><span data-bind="text: Sometext"></span></h2>
</li>
</ul>
<div data-bind="with: selectedItem">
<a data-bind="click: loadSomething">Do Something</a>
</div>
</div>
In my viewmodel i have this:
viewModel.selectItem= function (item) {
location.hash = "Action/" + item.id();
}
viewModel.loadSomething = function () {
location.hash = "Action/" + viewModel.someSelectedItem().id() +"/SubAction";
}
$.sammy(function () {
this.get('#Action', function () {
$.ajax({
url: '#Url.Action("GetMainView")',
type: "GET",
data: self.someId(),
dataType: "json",
success: function (result) {
$("#parentNode").html(result.message);
}
});
this.get('#Action/:id', function () {
var id = this.params["id"];
var matchItem = ko.utils.arrayFirst(viewModel.MainItems(), function (item) {
return item.id() == id;
});
viewModel.someSelectedItem(matchItem);
});
this.get('#Action/:id/SubAction', function () {
var id = this.params['id'];
$.ajax({
url: '#Url.Action("ViewSomething")',
type: "GET",
data: { id: id },
success: function (result) {
$('#parentNode').html(result.message);
}
});
});
});
Sample Code: https://skydrive.live.com/redir?resid=33048714B5BF3B4B!913
Steps to Reproduce:
Select "SubItems" under any of the items listed (Item 1, Item 2, Item 3)
Select any of the Sub Items that Label (Sub Item 1, Sub Item 2)
Partial View will be shown with "Sub Item {x}" with "Next View" link
Click "Next View" link.
"Next Partial View" will be shown.
Press the back button.
The thing I am trying to do is to load the SubItems and Select "Sub Item 1" view.
List item

I'm not sure this will work, but could you create a separate helper function to load the main view. Then it would be the case of the following:
this.get('#Action', function () {
LoadMainView();
}
this.get('#Action/:id', function () {
if($('#parentNode').length == 0) {
LoadMainView(function() {
var id = this.params["id"];
var matchItem = ko.utils.arrayFirst(viewModel.MainItems(), function (item) {
return item.id() == id;
});
viewModel.someSelectedItem(matchItem);
})
}
}
Your LoadMainView function would then accept a callback and be something like this:
function LoadMainView(callback) {
$.ajax({
url: '#Url.Action("GetMainView")',
type: "GET",
data: self.someId(),
dataType: "json",
success: function (result) {
$("#parentNode").html(result.message);
if(typeof callback == "function") {
callback();
}
}
});
}
I haven't been able to test this in your solution (I get an error opening it), but I believe that's the general structure to do what you are asking.

Related

Div shows/hides after second click with ajax and django

i want to have simple functionality in my app. When user clicks on "show replies" button, div with class "replies" will show up, then button changes to "hide replies" and when click it again the div will disappear. I am close but the problem is: when I click on button first time (after reloading page), the button changes to "hide", data is not showing up. Until i click it second time it shows and then i have data and button "show replies". In other words: ajax call doesn't work on first time, data prints properly even with first click. Please help me to understand what is wrong.
ajax
$(document).ready(function () {
$(".showReplies").click(function () {
let id = $(this).attr('id');
$.ajax({
url: $(this).attr("data-href"),
type: 'get',
success: function (data) {
console.log(data);
$(`#${id}.replies`).html(data);
let text = $(`#${id}.showReplies`).text()
if (text == 'Show replies') {
text = 'Hide replies'
$(`#${id}.showReplies`).text(text)
} else {
text = 'Show replies'
$(`#${id}.showReplies`).text(text)
}
}
})
});
});
template
<button type="button" id="{{ comment.id }}" class="showReplies btn btn-link" data-href="{% url 'comment_replies' comment.id %}">Show replies</button>
<div class="replies" id="{{ comment.id }}" style="margin-left: 30px;">
{% include 'blog/comment_replies.html' %}
</div>
urls
path('comment_replies/<int:comment_id>/', comment_replies, name='comment_replies')
view
def comment_replies(request, comment_id):
comment = Comment.objects.get(id=comment_id)
replies = Reply.objects.filter(comment=comment)
context = {'replies': replies}
return render(request, 'blog/comment_replies.html', context)
Ok, #Swati found the solution:
$(document).ready(function () {
$(".showReplies").click(function () {
let id = $(this).attr('id');
$.ajax({
url: $(this).attr("data-href"),
type: 'get',
success: function (data) {
console.log(data);
$(`#${id}.replies`).html(data);
let text = $(`#${id}.showReplies`).text();
console.log(text);
if (text == 'Show replies') {
text = 'Hide';
$(`#${id}.showReplies`).text(text);
$(`#${id}.replies`).show();
} else {
text = 'Show replies';
$(`#${id}.showReplies`).text(text);
$(`#${id}.replies`).hide();
}
}
})
});
});
I had to add $(#${id}.replies).show();and $(#${id}.replies).hide();in if and else.

Masonry view not working after loading more posts via ajax

I'm using this method to load more posts with Ajax.
I'm also using Masonry for the posts layout.
Masonry works fine for the first set of posts, but not for the next set of posts that are appended after clicking load more posts.
How can I make Masonry work after loading more posts?
Screen before click
Screen after click
Source Code:
index.php
<!-- Post Layout -->
<div class="posts <?php echo $home_style; ?>">
<!-- Normal Post -->
<?php
if (have_posts()) :
/* Start the Loop */
while (have_posts()) : the_post();
/* Home Layout */
if ($home_style === 'standard') {
get_template_part('inc/posts/content');
} else {
get_template_part('inc/posts/content', 'grid');
}
endwhile;
else :
get_template_part('template-parts/content', 'none');
endif;
?>
<?php
global $wp_query; // you can remove this line if everything works for you
// don't display the button if there are not enough posts
if ($wp_query->max_num_pages > 1)
// you can use <a> as well
echo '<div class="misha_loadmore grid-post">More posts</div>';
?>
</div>
<!-- Post Layout / END -->
Ajax Code
jQuery(function ($) {
$('.misha_loadmore').click(function () {
var button = $(this),
data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page': misha_loadmore_params.current_page
};
$.ajax({
url: misha_loadmore_params.ajaxurl, // AJAX handler
data: data,
type: 'POST',
beforeSend: function (xhr) {
// change the button text, you can also add a preloader image
button.text('Loading...');
},
success: function (data) {
if (data) {
button.text('More posts').prev().before(data); // insert new posts
misha_loadmore_params.current_page++;
if (misha_loadmore_params.current_page == misha_loadmore_params.max_page)
button.remove(); // if last page, remove the button
// you can also fire the "post-load" event here
// if you use a plugin that requires it
// $( document.body ).trigger( 'post-load' );
} else {
button.remove(); // if no data, remove the button as well
}
}
});
});
});
Masonry script.js
/* Masonary Grid */
$('.home-grid').masonry({
itemSelector: '.grid-post',
percentPosition: true,
gutter: 33
});
In most javascript libraries, if you change the DOM (HTML) after initializing the plugin, you will have to tell the library that changes have been made. Most libraries will include a function or listen to an event that tells it to update. In the case of Masonry, it looks like this function is reloadItems.
In your case, it looks like you will have to call $('.home-grid').masonry('reloadItems'); directly after you do button.text( 'More posts' ).prev().before(data);.
Full code:
jQuery(function ($) {
$('.misha_loadmore').click(function () {
var button = $(this),
data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page': misha_loadmore_params.current_page
};
$.ajax({
url: misha_loadmore_params.ajaxurl, // AJAX handler
data: data,
type: 'POST',
beforeSend: function (xhr) {
button.text('Loading...');
},
success: function (data) {
if (data) {
button.text('More posts').prev().before(data); // insert new posts
$('.home-grid').masonry('reloadItems');
misha_loadmore_params.current_page++;
if (misha_loadmore_params.current_page == misha_loadmore_params.max_page)
button.remove(); // if last page, remove the button
} else {
button.remove(); // if no data, remove the button as well
}
}
});
});
});

Make 2 AJAX calls on button Click

I am working on ASP.NET MVC project. In my home page, I have a search box with a search button.
When User types a Keyword and Click Search, I need to perform 2 independent search Operations (I am using Elasticseach, so two calls to Elasticsearch).
Make a call to SearchItems action method, which will go and get Items from Elasticsearch and returns ItemsPartialView.
Make a call to SearchCategory action method which goes and gets categories from Elasticsearch and returns CategoryPartialView.
In my home page, I want to make 2 ajax calls, to these action methods using AJAX, to display the result.
This Image explains what I want to achieve
Question: Is it possible to make 2 calls to 2 action methods on one event using AJAX?
It's possible. The only real issue is whether you want the ajax requests to be sent in a certain order (and the usual issues of efficiency of code to avoid repeats, the format of the data returned etc). One way of doing this (where the ajax second call is made after the first completes successfully) is sketched out:
<input type="text" id="search-query" value="" />
<button id="test-button">Test Ajax</button>
<div id="ajax-one-result"></div>
<div id="ajax-two-result"></div>
<script>
$(function(){
$(document).on("click", "#test-button", function(){
var qry = $("#search-query").val();
func1(qry);
function func1(queryString) {
var urlOne = "/Path/To/AjaxOne";
return $.ajax({
type: "GET",
url: urlOne,
timeout: 30000,
data: { query: queryString },
dataType: "json",
beforeSend: function () {
},
success: function (transport) {
$("#ajax-one-result").html(transport);
func2(transport);
console.log("AjaxOne success");
},
error: function (xhr, text, error) {
console.log("ERROR AjaxOne");
},
complete: function () {
}
});
}
function func2 (ajaxOneResult) {
var urlTwo = "/Path/To/AjaxTwo";
$.ajax({
type: "GET",
url: urlTwo,
timeout: 30000,
data: { query: ajaxOneResult },
dataType: "json",
beforeSend: function () {
},
success: function (transport) {
$("#ajax-two-result").html(transport);
console.log("AjaxTwo success");
},
error: function (xhr, text, error) {
console.log("ERROR AjaxTwo");
},
complete: function () {
}
});
}
});
});
</script>
with Controller Actions:
public async Task<JsonResult> AjaxOne(string query)
{
// For testing only
System.Threading.Thread.Sleep(5000);
var result = "AjaxOne Result: " + query;
return Json(result, JsonRequestBehavior.AllowGet);
}
public async Task<JsonResult> AjaxTwo(string query)
{
// For testing only
System.Threading.Thread.Sleep(2000);
var result = "AjaxTwo Result: " + query;
return Json(result, JsonRequestBehavior.AllowGet);
}

Rendering a partial view with ajax

Currently I have a main view called getRolesByYear.cshtml. In this view I have three buttons, each for an year. When I click a button(or on page load) I invoke a method, which takes an int 'year' for a parameter and calls an ajax with the year parameter. This ajax calls an action method (getRolesByYear, the one for the main view). The Action method makes a query to a database, a result of which is a list of ViewModel objects. In the return statement I return a PartialView like this : return PartialView("_yearlyRoles",list);. Sadly, after all this, instead of getting a list of the desired objects in my frontend, all i get is an error from the error part of the ajax call. I am generally a novice and I am very stuck with this.
Here is the main view getRolesByYear.cshtml:
#{
ViewBag.Title = "getRolesByYear";
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
getRolesForYear(parseInt(#DateTime.Now.Year));
$(function () {
$('#years a').click(function () {
var year = $(this).text();
console.log(year);
getRolesForYear(parseInt(year));
});
})
//console.log(year);
function getRolesForYear(year) {
console.log(year);
$.ajax({
type: "POST",
url: '#Url.Action("getRolesByYear", "WorkRoles")',
dataType: "json",
data: {
year: year
},
success: successFunc,
error: errorFunc
});
function successFunc(data, status) {
$("#partial").html(data);
}
function errorFunc() {
alert('error');
}
}
</script>
<div id = "years" class="btn-group btn-group-justified timeline">
#DateTime.Now.Year
#DateTime.Now.AddYears(-1).Year
#DateTime.Now.AddYears(-2).Year
</div>
<div id = "partial"></div>
The partial view :
#model IEnumerable<eksp.Models.RoleViewModel>
#foreach (var item in Model)
{
<div class="jumbotron">
<h2>item.Role.RoleName</h2>
<h1> item.Role.RoleDescription</h1>
<p class="lead">Focus start : item.Role.FocusStart</p>
<p>Focus end : item.Role.FocusStart </p>
</div>
}
The Action Method :
[HttpPost]
public ActionResult getRolesByYear(int year)
{
string currentUserId = User.Identity.GetUserId();
var list = db.WorkRoles.
Join(db.WorkRolesUsersDetails,
o => o.WorkRoleId, od => od.WorkRoleId,
(o, od) => new
{
WorkRoleId = o.WorkRoleId,
RoleName = o.RoleName,
RoleDescription = o.RoleDescription,
CompanyId = o.CompanyId,
WRUDId = od.WRUDId,
UserDetailsId = od.UserDetailsId,
FocusStart = od.FocusStart,
FocusEnd = od.FocusEnd
}).ToList()
.Select(item => new RoleViewModel(
item.WorkRoleId,
item.RoleName,
item.RoleDescription,
item.CompanyId,
item.WRUDId,
item.UserDetailsId,
item.FocusStart,
item.FocusEnd)).ToList();
//RoleViewModel rv = list;
if (Request.IsAjaxRequest())
{
return PartialView("_yearlyRoles", list);
}
else
{
return View(list);
}
}
Given the reported error message, you need to alter your ajax call. By setting "data" parameter to "json" you're telling ajax to expect JSON-formatted data back in the response, but a partial view is HTML, so change your ajax call to reflect this:
$.ajax({
type: "POST",
url: '#Url.Action("getRolesByYear", "WorkRoles")/' + year,
dataType: "html", //set the correct data type for the response
success: successFunc,
error: errorFunc
});
As an aside, you can improve your error handling on the client side quite straightforwardly by changing errorFunc to something like this, using the parameters that are provided to the callback by $.ajax:
function errorFunc(jQXHR, textStatus, errorThrown) {
alert("An error occurred while trying to contact the server: " + jQXHR.status + " " + textStatus + " " + errorThrown);
}
For less instrusive reporting and/or easier debugging, you could change the alert to console.log. To get more detail you could also log the entire jQXHR object:
console.log(JSON.stringify(jQXHR));

How to associate an event to Html.ActionLink in MVC3

I have made an Ajax function but i am getting a big prolem in that.
I was displaying the contents on click of the link..
The links are fetched from the database and also the url of the links are fetched from the datbase.
I have wriiten ajax to call the contents dynamically on click of the link
<script type="text/javascript">
$(document).ready(function () {
$('a').click(function (e) {
e.preventDefault();
var filename = $(this).text();
var Hobbyurl = '#Url.Action("FetchUrlByHobbyName")';
$.ajax({
type: "POST",
url: Hobbyurl,
data: { data: filename },
success: function (returndata) {
$('iframe').attr('src', returndata);
}
});
});
});
</script>
Now FetchUrlByHobbyName is the function called from the Controller thart returns the url
//Ajax routine to fetch the hobbyinfo by hobbyname
[HttpPost]
public ActionResult FetchUrlByHobbyName(string data)
{
HobbyMasters hobbymaster = new HobbyHomeService().FetchHobbyMasterByHobbyName(data);
string url = hobbymaster.InformationUrl;
if (HttpContext.Request.IsAjaxRequest())
return Json(url);
return View();
}
And in my View i have written the link like this:
#foreach (var item in Model)
{
<li >#Html.ActionLink(item.HobbyName, "Hobbies")
</li>
}
i tried this :
#Html.ActionLink(item.HobbyName, "Hobbies", null, new { id = "alink" })
and then calling Ajax on click of 'alink' but with this my ajax function doesnot get called.
Now the problem is the ajax function is getting called on click of every link on the page..
I want to assign a unique Id to it but i am not understanding how to do that
please Help me...
For that specific link, assign an id. E.g
<a id="someID" href="url">Link</a>
and than bind the click only with that link.
$('#someID').click(function (e)) ....
If I understood you correctly this helps you
The text of the link
<script type="text/javascript">
function myAjaxFunction(){
e.preventDefault();
var filename = $(this).text();
var Hobbyurl = '#Url.Action("FetchUrlByHobbyName")';
$.ajax({
type: "POST",
url: Hobbyurl,
data: { data: filename },
success: function (returndata) {
$('iframe').attr('src', returndata);
}
});
</script>
Try to give a css class selector to you action link like this...
#Html.ActionLink("some link", "Create", "Some_Controller", new { }, new { #class = "test" })
then User jquery for it..
<script type="text/javascript">
$(document).ready(function () {
$('.test').click(function (e) {
e.preventDefault();
var filename = $(this).text();
var Hobbyurl = '#Url.Action("FetchUrlByHobbyName")';
$.ajax({
type: "POST",
url: Hobbyurl,
data: { data: filename },
success: function (returndata) {
$('iframe').attr('src', returndata);
}
});
});
});
</script>

Resources