asp.net mvc + knockout + ajax partial load + reuse viewodel and load different data within the same page - asp.net-mvc

In a single asp.net MVC page, I've to show 3 reports of same layout/structor. So I created a page that generated a report using Knockout databind and 10 reports are generated by passing some additional parameters.
I tried to load all 3 reports using Ajax partial view and by this way I'm populating those 10 reports in one single page.
Now I happen to see a strange issue, the last report data appears for all the 3 reports though the data for each report is different. Anyone knows how to handle this issue ?
Main Page View, where I call 3 reports via Ajax call.
<div id="RecentlyAddedReport" ></div>
<div id="RecentlyConsultedReport"></div>
<div id="RecentlyPrescribedReport"></div>
<!-- start here -->
<script type="text/javascript">
$(document).ready(function () {
AjaxLoadReport('RecentlyAddedReport', 'Patient/Report?type=RecentlyAdded&name=Recently Added');
AjaxLoadReport('RecentlyConsultedReport', 'Patient/Report?type=RecentlyConsulted&name=Recently Consulted');
AjaxLoadReport('RecentlyPrescribedReport', 'Patient/Report?type=RecentlyPrescribed&name=Recently Prescribed');
});
function AjaxLoadReport(reportType, actionURL) {
var resultDiv = $('#' + reportType);
$.ajax({ type: "GET", url: actionURL, data: {},
success: function (response) {
resultDiv.html('');
resultDiv.html(response);
}
});
}
</script>
Report View - I call this same view for all the 3 reports
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<TryHomeo.Web.UI.Models.UserControlViewData>" %>
<script type="text/javascript" src="../../scripts/jquery-1.7.1.min.js"></script>
<script src="../../Scripts/jquery.timeago.js" type="text/javascript"> </script>
<script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"> </script>
<h1>
<%:Model.ReportName%>
</h1>
<div class='loadingIndicator' title="Loading..."></div>
<ul id="<%=Model.ReportType %>" data-bind="template: { name: 'patient-template', foreach: patients}"></ul>
<script type="text/html" id="patient-template">
<span>
<li>
<div>
<a data-bind="text: PatientName"></a>- (<abbr class='timeago' data-bind="timeago: DatedString"></abbr>)
</div>
</li>
</span>
</script>
<script type="text/javascript">
// ReportViewModel View Model //
function ReportViewModel() {
var self = this;
self.patients = ko.observableArray([]);
}
var objVM = new ReportViewModel();
ko.applyBindings(objVM);
// Using jQuery for Ajax loading indicator
$(".loadingIndicator").ajaxStart(function () { $(this).fadeIn(); }).ajaxComplete(function () { $(this).fadeOut(); });
$(document).ready(function () {
$.ajax({
dataType: 'json',
url: '/Patient/GetPatientReport/?type=' + '<%=Model.ReportType %>' + '&' + '<%=DateTime.Now.ToString() %>',
success: SetData,
error: function (xhr, ajaxOptions, thrownError) { alert(xhr.status); alert(thrownError); }
});
});
function SetData(data) {
objVM.patients(data);
}
ko.bindingHandlers.timeago = {
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var $this = $(element);
// Set the title attribute to the new value = timestamp
$this.attr('title', value);
// If timeago has already been applied to this node, don't reapply it -
// since timeago isn't really flexible (it doesn't provide a public
// remove() or refresh() method) we need to do everything by ourselves.
if ($this.data('timeago')) {
var datetime = $.timeago.datetime($this);
var distance = (new Date().getTime() - datetime.getTime());
var inWords = $.timeago.inWords(distance);
// Update cache and displayed text..
$this.data('timeago', { 'datetime': datetime });
$this.text(inWords);
} else {
// timeago hasn't been applied to this node -> we do that now!
$this.timeago();
}
}
};
</script>

Related

Redirect before selecting an item Select2

I'm using Select2 v4.0.3 and I populate the element using ajax.
$("#el").select2({
multiple: true
maximumSelectionSize: 1,
ajax: {
url: url,
data: function (params) {
return {
name: params.term
};
},
processResults: function (data) {
return {
results: $.map(data.results, function(obj) {
return {id: obj.id, text: obj.name, key: obj.key};
}
})
};
}
}
});
I want to redirect the client before a result is selected. The problem is I need the key attribute from the clicked result. To understand better what I want to do, I paste here a snippet that works after the selection is made.
$("#el").on("select2:select", function(e) {
var selected = $(this).select2('data')[0];
location.href = base_url + '?key=' + selected.key;
});
You can use event.params.args.data.id to get the key attribute from the clicked result. So, your code would probably work like:
$("#el").on("select2:select", function(e) {
var selected = event.params.args.data.id;
location.href = base_url + '?key=' + selected;
});
I slightly modified the official Github repositories example to show my point.
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
</head>
<body>
<select class="js-data-example-ajax" style="width: 100%">
<option value="3620194" selected="selected">select2/select2</option>
</select>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<script>
$(".js-data-example-ajax").select2({
ajax: {
url: "https://api.github.com/search/repositories",
dataType: 'json',
delay: 250,
data: function(params) {
return {
q: params.term, // search term
page: params.page
};
},
processResults: function(data, params) {
// parse the results into the format expected by Select2
// since we are using custom formatting functions we do not need to
// alter the remote JSON data, except to indicate that infinite
// scrolling can be used
params.page = params.page || 1;
return {
results: $.map(data.items, function(ghrepo) {
return {
text: ghrepo.archive_url,
id: ghrepo.archive_url
}
})
}
},
cache: true
},
escapeMarkup: function(markup) {
return markup;
},
minimumInputLength: 1
}).on('select2:selecting', function(event, params) {
event.preventDefault();
repoId = event.params.args.data.id;
console.log(repoId);
});
</script>
</body>
</html>

How to show autocomplete search result as a link

I have successfully implemented autocomplete search option in my laravel project "book shop managing". Again from my homepage if I click on the name of a book then it would show the specific book. But how can I add link to my search result, so that if I click on a book from the result then it would take me to the page that contains the book details.
my index.blade.php
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script>
$(function() {
$( "#books" ).autocomplete({
source: 'auto_complete'
});
});
</script>
<div class="ui-widget">
<label for="books">Books: </label>
<input id="books">
</div>
controller
public function search(){
$search = Input::get('term');
$books = Book::where('title','like','%'.$search.'%')->get();
foreach ($books as $book) {
$data[] = $book->title;
}
// return $books;
return $data;
}
route
Route::get('auto_complete', 'BooksController#search');
CONTROLLER
public function search(){
$search = Input::get('term');
// return $search or dd($search) check if request get the value please
$books = Book::where('title','like','%'.$search.'%')->get();
// return $books or dd($books) check if request get the values please
$results = array();
foreach($books as $key => $v){
$results[]=['id' => $v->id];
}
// return a json object
return response()->json([
'suggestions'=>$results]);
}
JS
$(function() {
$( "#books" ).autocomplete({
source: 'auto_complete',
onSelect: function (data) {
location.href = "www.yourwebsite.com+data.suggestions.id" // this redirect for example book id:1 to www.yourwebsite.com/1
// Or use jquery to redirect: window.location.replace("http://stackoverflow.com");
}
});
});
Use the same route, let me know if there is some error in network or console!
I supposed that you integrated the jquery library and autocomplete library js :)

Dymanic listview construction visible in jQuery Mobile 1.4.2 transition

I have a Single Page transition from #homepage to #addresses where the page #addresses include a dynamic listview build based in an $.ajax WebApi call.
The problem is that it's visible the construction of the listview when we arrive at the second page, and I want to avoid that, I want the list all build when we land in the #addresses page.
I also have a delay click in the listview in iPhone.
My code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>izigo.mobile</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css">
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
$(document).bind("mobileinit", function ()
{
$.mobile.toolbar.prototype.options.addBackBtn = true;
$.mobile.toolbar.prototype.options.backBtnText = "voltar";
$.mobile.page.prototype.options.domCache = true;
});
</script>
<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>
<script>
/* Pass data with changePage */
$(document).on("pageinit", "#homepage", function ()
{
$(".category").on("click", function ()
{
$.mobile.pageContainer.pagecontainer("change", "#addresses",
{
categoryId: this.id,
transition: "slide"
});
});
});
/* retrieve data and run function to add elements */
$(document).on("pagebeforechange", function (e, data)
{
if (data.toPage[0].id == "addresses")
{
var categoryId = data.options.categoryId;
clearListCategory("#addresses");
buildListCategory("#addresses", categoryId);
}
});
function clearListCategory(page)
{
var $page = $(page);
$("ul", $page).remove();
}
function buildListCategory(page, categoryId)
{
$.ajax({
type: "POST",
url: "http://10.0.0.200/api/Mobile/GetAddresses",
crossDomain: false,
beforeSend: function () { $.mobile.loading('show') },
complete: function () { $.mobile.loading('hide') },
data: { CategoryId: categoryId },
dataType: 'json',
success: function (addresses)
{
showAddresses(page, addresses);
},
error: function () {
console.log("loadList error!");
}
});
}
function showAddresses(page, addresses)
{
var $page = $(page);
var list = $("<ul/>", {
"data-role": "listview"
});
var items = '';
$.each(addresses, function (i, address)
{
items = $("<li>" + address.Name + "</li>");
list.append(items);
});
$(".ui-content", $page).append(list);
$("ul", $page).listview();
}
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- home-page -->
<div data-role="page" id="homepage">
<div data-role="header" data-position="fixed"><h1>mobile</h1></div>
<div class="ui-content" role="main">
<ul data-role="listview" id="categories">
<li>Oficina</li>
<li>Seguro</li>
<li>Reboque</li>
</ul>
</div>
</div>
<!-- page addresses list -->
<div data-role="page" id="addresses">
<div data-role="header" data-position="fixed"><h1>mobile</h1></div>
<div class="ui-content" role="main"></div>
</div>
</body>
</html>
The code you're using, you populate listview on pagebeforechange event, which is triggered before any other page event. You should populate listview before you navigate to target page, using .success or .complete callback.
$.ajax({
type: "POST",
url: "URL",
crossDomain: false,
beforeSend: function () {
$.mobile.loading('show')
},
complete: function () {
$.mobile.loading('hide')
},
data: {
CategoryId: categoryId
},
dataType: 'json',
success: function (addresses) {
showAddresses(page, addresses);
$.mobile.pageContainer.pagecontainer("change", "#addresses");
},
error: function () {
console.log("loadList error!");
}
});
Demo - Code

DropDownListFor automatic postback

How would I implement something like automatic postback for DropDownListFor in MVC. Currently, after selecting a value in dropdown I have to refresh the page to see the changes applied to the page.
In View,
The dropdownlistfor is like
#Html.DropDownListFor(m => m.SelectedItem, Model.MyItemList, new { #id = "DropDownListForId"})
and the onchange event is handled as such
<script type = "text/javascript">
$(function () {
$('#DropDownListForId').change(function () {
var item = $(this).val();
$.ajax({
url: '#Url.Action("SomeAction", "SomeController")',
type: 'GET',
data: { value: item },
success: function(result) {
}
});
});
});
</script>
Thanks!
I think you can simply achieve this by submitting form on change event of DropDownList
Assuming myForm as you form id
<script type = "text/javascript">
$(function () {
$('#DropDownListForId').change(function () {
$('form#myForm').submit();
});
});
</script>

slideToggle and jQuery Ajax - New elements inoperable

When I introduce new elements to my slideToggle they look fine and are active (expanded by default) however if I click a pre-existing element all elements collapse and I cannot expand the new ajax elements. Essentially the new ajax elements are not part of the slideToggle group because that was constructed before the elements were introduced. How do I rebuild the toggle on the fly or make the new elements behave as expected?
** jQUERY
$('div.menu_body:eq(0)').show();
$('.acc .head:eq(0)').show().css({color:"#2B6893"});
$(".acc .head").click(function() {
$(this).css({color:"#2B6893"}).next("div.menu_body").slideToggle(300).siblings("div.menu_body").slideUp("slow");
$(this).siblings().css({color:"#404040"});
});
** Ajax
<script type="text/javascript">
jQuery(document).ready(function() {
setInterval("showNewFeeds()", 10000);
});
showNewFeeds() {
$.ajax({
type: 'POST',
url: 'feed.php',
data : {uid : '145', mid: '22', nid: 56'},
success: function(response) {
$('#feedNote').html(response).fadeIn('slow');
},
error: function (xhr, ajaxOptions, thrownError) {
//alert(xhr.status);
//alert(thrownError);
}
});
}
</script>";
** HTML
<div class="widget acc" id="feedNote">
<div class="head"><h5>Header 1</h5></div>
<div class="menu_body">
<div>HTML 1</div>
</div>
<div class="head"><h5>Header 2</h5></div>
<div class="menu_body">
<div>HTML 2</div>
</div>
</div>
Try :
$(document).on('click', '.acc .head', function() {
$(this).css({color:"#2B6893"}).next("div.menu_body").slideToggle(300).siblings("div.menu_body").slideUp("slow");
$(this).siblings().css({color:"#404040"});
});
instead of .click(function(){...})

Resources