Loading Remote Data in Select2 - asp.net-mvc-4

I am using Select2's Loading Remote Data Functionality.The problem is that data is not getting loaded on the dropdownlist.On keypress remote function is getting called and data is returning properly,but its not showing in dropdownlist.
HTML
<div class=" form-group col-md-4" data-url="#Url.Action("GetStudentWalkInnName")" id="WalkinnName">
<div>
<label for="txtEmployee" class=" control-label">
Name
</label>
</div>
<div>
<select class="form-control " id="ddlName"></select>
</div>
</div>
Jquery
//REGISTRATION=>INDEX.JS
$(function () {
var ddlNameUrl=$("#WalkinnName").data("url");
$("#ddlName").select2({
placeholder: "Search for Name",
minimumInputLength: 1,
ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
url: ddlNameUrl,
type: "POST",
dataType: 'json',
data: function (params) {
return {
term: params.term, // search term
page: params.page
};
},
processResults: function (data, params) {
params.page = params.page || 1;
return {
results: data,
};
}
}
});
});
Controller is
public JsonResult GetStudentWalkInnName(string term)
{
try
{
var walkInnNameList = _db.StudentWalkInns
.Where(s => s.CandidateName.StartsWith(term))
.Select(x => new
{
Id=x.Id,
Text=x.CandidateName
}).ToList();
return Json(walkInnNameList, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json("", JsonRequestBehavior.AllowGet);
}
}
Any help will be highly appreciated.

According to the documentation, the format if the data should be an array of objects with names id and name i.e. lowercase (not Id and Name).
Change you query to
var walkInnNameList = _db.StudentWalkInns
.Where(s => s.CandidateName.StartsWith(term))
.Select(x => new
{
id = x.Id,
text = x.CandidateName
}); // .ToList() should not be necessary

Related

data in Vue instance doesn't get updated after axios post response

I am writing a code piece to submit the html form data on a POST REST API. Using Vue.js and axios for that.
My Vue.js code is like this -
const app = new Vue({
el: "#main-div",
data() { return {
name: 'Please enter the name',
showEdit: true,
showResponse: true,
responseText: null
}
},
methods: {
savePerson: function () {
this.showEdit = false;
axios
.post('/api/person', {
name: this.name
})
.then(function (response) {
this.responseText = response.data.name+ ' added successfully.';
console.log(response);
console.log(response.data.name+ ' added successfully.');
})
.catch(function (error) {
this.responseText = error.message;
console.log(error);
});
}
}
}
)
And html -
<div id="main-div">
<h2> Fill out the details to create a Person</h2>
<div v-if="showEdit">
<form >
<div>
Name: <input v-bind:value = 'name' type="text" v-on:focus="name= ''" />
</div>
<div>
<button v-on:click="savePerson">Save</button>
</div>
</form>
</div>
<div v-if="showResponse">
<div><p>{{ responseText }}</p></div>
<div>
<button v-on:click="showEdit = true">Add one more person</button>
</div>
</div>
This code doesn't update responseText. That I can check in Vue plugin in browser.
Any idea what is not correct in my example?
You need to use an arrow function in the callback or else the function injects its own this context:
.then((response) => {
...
})
.catch((error) => {
...
})
Or you could use async/await:
async savePerson() {
this.showEdit = false;
try {
const response = await axios.post('/api/person', {
name: this.name
})
this.responseText = response.data.name+ ' added successfully.';
} catch(error) {
this.responseText = error.message;
}
}
to bind data with the input field you need to use v-model in the HTML and try to use the arrow function in the API call.

Vue js http request loop

I'm trying to create a live search form which is calling a http request whenever there is user input. So far the live searching works well, but the http request results in a loop. This problem shows up when I'm assigning the catalog_items to this.items.
Vue.js
Vue.filter('searchFor', function (value, searchString) {
var result = [];
if(!searchString || searchString.length < 2){
return value;
}
searchString = searchString.trim().toLowerCase();
this.fetchData(searchString);
result = this.items;
return result;
})
new Vue({
el: '#searchform',
data: {
searchString: "",
items: []
},
methods: {
fetchData: function (name) {
this.$http.get('api_url' + name )
.then(function(response){
var data = response.data;
var catalog_items = data['catalog_items'];
this.items = catalog_items;
})
}
}
})
The html search input:
<input type="text" v-model="searchString" placeholder="Enter your search terms" />
<ul>
<li v-for="item in catalog_items | searchFor searchString">
<p>#{{item.name}}</p>
</li>
</ul>
Thanks in advance!

Single file upload using Ajax, MVC 5 and jQuery

I am using asp.net MVC 5 to do a simple single file upload using the HTML element.I make an AJAX post request.The form has other fileds in addition to the file element.I tried diffrent methods available on the internet ,but nothing seems to be working.Is this really possible using the element?Using a jQuery plugin is my last option.I like to make things simple in my application
my HTML
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "form-person-edit-modal", enctype = "multipart/form-data" }))
{
<div class="row">
<div class="row">
<div class="small-4 columns">
#Html.GenericInputFor(m => m.Name, Helpers.HtmlInputType.Text, new { id = "input-name" })
</div>
<div class="small-4 columns">
#Html.GenericInputFor(m => m.Description, Helpers.HtmlInputType.TextArea, new { id = "input-description" })
</div>
<div class="small-4 columns">
<label>Choose File</label>
<input type="file" name="attachment" id="attachment" />
</div>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<input type="submit" id="image-submit" value="Save"/>
</div>
</div>
}
-- C# ViewModel
public class Person
{
Public string Name{get;set;}
Public string Description{get;set;}
public HttpPostedFileBase Attachment { get; set; }
}
-- Jquery Ajax Post:
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
success: function (data, textStatus, jqXHR) {
if (data.Success) {
success(data, textStatus, jqXHR);
} else {
if (error) {
error();
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (error)
error();
}
});
-- Javacsript where I try to get the file content,before passing that data to the above method
function getData(){
return {
Name:$('#input-name').val(),
Description:$('#input-description').val(),
Attachment:$('#form-ticket-edit-modal').get(0).files[0]
};
}
But the Attachment on the controller is null.I tried this as below,but doesnt seem to be working
[HttpPost]
public ActionResult Edit(ViewPerson person,HttpPostedFileBase attachment)
{
}
Is this still possible,or should I use a jQuery plugin(If so,which one do you recommend?)
I have used your code to show how to append image file,Please use Formdata() method to append your data and File and send through ajax.
Try Changing as per your requirement.
$("#SubmitButtonID").on("click",function(){
var mydata=new Formdata();
mydata.append("Name",$("#name").val());
mydata.append("Image",Image.files[0]);
alert(mydata);
$.ajax({
url: "#url.Action("ActionMethodName","ControllerName")",
type: 'POST',
contentType:false,
processData;false,
data: mydata,
dataType: 'json',
success: function (data, textStatus, jqXHR) {
if (data.Success) {
success(data, textStatus, jqXHR);
} else {
if (error) {
error();
}
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (error)
error();
}
});
});
<input type="file" id="Image" name="file">
<input type="button" id="SubmitButtonID" value="submit"/>

cannot remove knockout observableArray item with SingalR

I am struggling with two issues. The first one is that after I pushed a new item into observableArray and try to refresh the accordion. The new item did not show up in the accordion. But the producs().length increased by one.
this.hub.client.productAdded = function (p) {
products.push(new productListViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
//loadAccordion();
};
My second issue is that After SignalR deleted an item in the database and returned with the deleted object I tried to remove the deleted object from the observableArray. I have tried different ways and none of them work.
this.hub.client.productRemoved = function (deleted) {
//var deleted = ko.utils.arrayFilter(products(), function (item) {
// return item.id == deleted.id;
//})[0];
products.remove(function (item) { return item.id == deleted.id; });
//products.remove(deleted);
$("#accordion").accordion("refresh");
};
What do I miss here? Below is the whole page code for reference
#{
ViewBag.Title = "SignalR";
}
<h2>SignalR</h2>
<div id="error"></div>
<h2>Add Product</h2>
<form data-bind="submit: addProduct">
<input data-bind="value: newProductText" class="ui-corner-all" placeholder="New product name?" />
<input type="submit" class="ui-button" value="Add Product" />
</form>
<h2>Our Products</h2>
listed: <b data-bind="text: productCount"></b> product(s)
#*<div id="accordion" data-bind="template: {name: productTemplate, foreach: products }, visible: products.Length > 0"></div>*#
<div id="accordion" data-bind='template: {name: "product-template", foreach: products }'></div>
<script type="text/html" id="product-template">
<h3 data-bind="text: name"></h3>
<div>
<input type="button" class="ui-button" value="Remove Rroduct" data-bind="click: removeProduct" />
</div>
</script>
<span data-bind="visible: productCount() == 0">What? No products?</span>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/signalr")
<script src="/Scripts/jquery.signalR-2.0.1.min.js" type="text/javascript"></script>
<script src="~/signalr/hubs" type="text/javascript"></script>
<script src="/Scripts/jquery.livequery.min.js"></script>
<style>
#accordion {width: 300px;}
#accordion h3 { padding-left: 30px}
</style>
<script>
function productViewModel(id, name, ownerViewModel) {
this.id = ko.observable(id);
this.name = ko.observable(name);
var self = this;
this.removeProduct = function () { ownerViewModel.removeProduct( id); };
this.name.subscribe(function (newValue) {
ownerViewModel.updateProduct(ko.toJS(self));
});
}
function productListViewModel() {
this.hub = $.connection.products;
this.products = ko.observableArray([]);
this.newProductText = ko.observable();
chat = this.hub
var products = this.products;
var self = this;
// Get All
this.init = function () {
this.hub.server.getAll();
}
this.hub.client.productAll = function (allProducts) {
//var mappedProducts = $.map(allProducts, function (item) {
// return new productViewModel(item.id, item.name, self);
//});
//products(mappedProducts);
$.each(allProducts, function (index, item) {
products.push(new productViewModel(item.id, item.Name, self));
});
loadAccordion();
};
this.hub.reportError = function (error) {
$("#error").text(error);
};
$.connection.hub.error(function (error) {
console.log('SignalR error: ' + error)
});
this.hub.client.productAdded = function (p) {
products.push(new productListViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
//loadAccordion();
};
this.hub.client.productRemoved = function (deleted) {
//var deleted = ko.utils.arrayFilter(products(), function (item) {
// return item.id == deleted.id;
//})[0];
products.remove(function (item) { return item.id == deleted.id; });
//products.remove(deleted);
$("#accordion").accordion("refresh");
};
// Commands
this.addProduct = function () {
var p = { "Name": this.newProductText() };
this.hub.server.add(p).done(function () { }).fail(function (e) { alert(e); });
this.newProductText("");
};
this.removeProduct = function (id) {
this.hub.server.remove(id).done(function () { alert("aa"); }).fail(function (e) { alert(e+" aa"); });
};
this.productCount = ko.dependentObservable(function () {
return products().length;
}, this);
}
function loadAccordion() {
$("#accordion").accordion({ event: "mouseover" });
}
$(function () {
var viewModel = new productListViewModel();
ko.applyBindings(viewModel);
// connect SinalR
$.connection.hub.start(function () { viewModel.init(); });
//$.connection.hub.start(function () { chat.server.getAll(); });
});
</script>
}
To solve your add problem: you are creating a new productListViewModel but you need to add a new productViewModel, so you just need to create the correct viewmodel:
this.hub.client.productAdded = function (p) {
products.push(new productViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
};
To solve your delete problem: in your productViewModel the id is a ko.observable so you need to write item.id() to access its value in the remove function:
this.hub.client.productRemoved = function (deleted) {
products.remove(function (item) { return item.id() == deleted.id; });
$("#accordion").accordion("refresh");
};

knockout.js binding issue when trying to refresh data

I am using knockout.js data binding. At the page load the binding works fine and data is shown on the page correctly. Then I try to push data back to the database and the push is successful. The database receives the data OK.
The problem comes when I try to reload the data upon push success. At this time the binding already happen once (at the page load). If I don't bind it again the data on the page does not refresh. If I do the binding again knockout.js issues an error "cannot bind multiple times". If I do a cleanup before rebinding I receive an error "nodeType undefined".
Can anyone tell me what I have missed here? I am using ASP.NET MVC 4.0 with knockout.js 3.0.0.
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplJSON.Controllers
{
public class KnockoutController : Controller
{
//
// GET: /Knockout/
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetProductList()
{
var model = new List<Product>();
try
{
using (var db = new KOEntities())
{
var product = from p in db.Products orderby p.Name select p;
model = product.ToList();
}
}
catch (Exception ex)
{ throw ex; }
return Json(model, JsonRequestBehavior.AllowGet);
}
// your controller action should return a JsonResult. There's no such thing as a controller action that returns void. You have specified dataType: 'json' so return JSON. That's it. As far as what parameter this controller action should take, well, from the JSON you are sending ({"Name":"AA"}) it should be a class that has a Name property of type string.
// modify your action signature to look like this: [HttpPost] public ActionResult SaveProduct (Product product) { ... return Json(new { success = true }); }. Or get rid of this dataType: 'json' attribute from your AJAX request if you don't want to return JSON. In this case you could return simply status code 201 (Created with empty response body): return new HttpStatusCodeResult(201);.
[HttpPost]
public ActionResult SaveProduct(Product product)
{
using (var db = new KOEntities())
{
db.Products.Add(new Product { Name = product.Name, DateCreated = DateTime.Now });
db.SaveChanges();
}
return Json(new { success = true });
}
}
}
View:
#{
ViewBag.Title = "Knockout";
}
<h2>Knockout</h2>
<h3>Load JSON Data</h3>
<div id="loadJson-custom" class="left message-info">
<h4>Products</h4>
<div id="accordion" data-bind='template: { name: "product-template", foreach: product }'>
</div>
</div>
<h3>Post JSON Data</h3>
<div id="postJjson-custom" class="left message-info">
<h4>Add Product</h4>
<input id="productName" /><br />
<button id="addProduct">Add</button>
</div>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/livequery")
<script src="/Scripts/jquery.livequery.min.js"></script>
<style>
#accordion { width: 400px; }
</style>
<script id="product-template" type="text/html">
<h3><a data-bind="attr: {href:'#', title: Name, class: 'product'}"><span data-bind="text: Name"></span></a></h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span> </p>
</div>
</script>
<script>
var isBound;
function loadJsonData() {
$.ajax({
url: "/knockout/GetProductList",
type: "GET",
contentType: "application/json",
dataType: "json",
data: {},
async: true,
success: function (data) {
var loadJsonViewModel = {
product: ko.observableArray(),
init: function () {
loadAccordion();
}
};
var a = $('loadJson-custom');
loadJsonViewModel.product = ko.mapping.fromJS(data);
if (isBound) { }
else
{
ko.applyBindings(loadJsonViewModel, $('loadJson-custom')[0]);
isBound = true;
}
loadJsonViewModel.init();
}
});
}
// push data back to the database
function pushJsonData(productName) {
var jData = '{"Name": "' + productName + '"}';
$.ajax({
url: "/knockout/SaveProduct",
type: "POST",
contentType: "application/json",
dataType: "json",
data: jData,
async: true,
success: function (data, textStatus, jqXHR) {
console.log(textStatus + " in pushJsonData: " + data + " " + jqXHR);
//ko.cleanNode($('loadJson-custom')[0]);
loadJsonData();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus + " in pushJsonData: " + errorThrown + " " + jqXHR);
}
});
}
function loadAccordion() {
$("#accordion > div").livequery(function () {
if (typeof $("#accordion").data("ui-accordion") == "undefined")
{
$("#accordion").accordion({ event: "mouseover" });
}
else
{
$("#accordion").accordion("destroy").accordion({ event: "mouseover" });
}
});
}
$(function () {
isBound = false;
loadJsonData();
$("#addProduct").click(function () {
pushJsonData($("#productName").val());
});
});
</script>
}
Here is a complete solution for your question.
I have just implemented and checked.
Please have a look.
I have created a class for getting some records ie: Records.cs.
public static class Records
{
public static IList<Student> Stud(int size)
{
IList<Student> stud = new List<Student>();
for (int i = 0; i < size; i++)
{
Student stu = new Student()
{
Name = "Name " + i,
Age = 20 + i
};
stud.Add(stu);
}
return stud;
}
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
Here is a controller for the respective view.
//
// GET: /HelpStack/
private static IList<Student> stud = Records.Stud(10);
public ActionResult HelpStactIndex()
{
return View();
}
[HttpGet]
public JsonResult GetRecord()
{
return Json(stud, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public void PostData(Student model)
{
//do the required code here as All data is in "model"
}
Here is a view as HTML, I have taken two section one for list and other to Add records
<div id="loadJson-custom">
<h4>Student</h4>
<table width="100%">
<tr>
<td style="width: 50%">
<div id="accordion" data-bind='template: { name: "product-template", foreach: Student }'>
</div>
</td>
<td valign="top">
<div id="NewStudent">
<input type="text" data-bind="value: Name" /><br />
<input type="number" data-bind="value: Age" /><br />
<input type="submit" data-bind="click: Save" value="AddNew" />
</div>
</td>
</tr>
</table>
Here is your scripts for Knockoutjs.
<script id="product-template" type="text/html">
<h3><a data-bind="attr: { href: '#', title: Name, class: 'product' }"><span data-bind=" text: Name"></span></a>
<br />
Age: <span data-bind="text: Age"></span>
</h3>
<div>
<p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span></p>
</div>
</script>
<script type="text/javascript">
//Model for insert new record
var Model = {
Name: ko.observable(''),
Age: ko.observable(''),
};
var Student = ko.observableArray([]); // List of Students
function loadData() { //Get records
$.getJSON("/HelpStack/GetRecord", function (data) {
$.each(data, function (index, item) {
Student.push(item);
});
}, null);
}
function Save() { //Save records
$.post("/HelpStack/PostData", Model, function () { //Oncomplete i have just pushed the new record.
// Here you can also recall the LoadData() to reload all the records
//Student.push(Model);
Student.unshift(Model); // unshift , add new item at top
});
}
$(function () {
loadData();
ko.applyBindings(Model, $('#NewStudent')[0]);
});
</script>
You are declaring your model inside loadJsonData function success callback, & creating new object on every success callback, move the model outside that function, create an object & use it inside loadJsonData function, it will fix the issue.