MVC 5, Ajax, Jquery - script works only once - javascript

<script>
$(function () {
var ajaxSubmit = function () {
var $form = $(this);
var settings = {
data: $(this).serialize(),
url: $(this).attr("action"),
type: $(this).attr("method")
};
$.ajax(settings).done(function (result) {
var $targetElement = $($form.data("ajax-target"));
var $newContent = $(result);
$($targetElement).replaceWith($newContent);
$newContent.effect("slide");
});
return false;
};
$("#search-form").submit(ajaxSubmit);
});
</script>
Ok, This script is for searching some content from databse. it works great, but only once. When im trying to hit submit again in my from, its not working again. Only when I refresh page.
Could someone help me?
My from in same index.cshtml file:
<div>
<form id="search-form" method="get" data-ajax="true" data-ajax-target="#zawartosc" data-ajax-update="#zawartosc">
<input id="search-filter" type="search" name="searchQuery"
data-autocomplete-source="#Url.Action("MiejscaPodpowiedzi", "Miejsce")"
placeholder="Wprowadź tekst, aby filtrować..." />
<input type="submit" id="send" value="Send" />
</form>
<div id="zawartosc">
#Html.Partial("_ListaMiejsc")
</div>
My controller:
public class HomeController : Controller
{
private DaneKontekst db = new DaneKontekst();
public ActionResult Index(string searchQuery = null)
{
var miejscaNaSwiecie = db.MiejscaNaSwiecie.Where(o => (searchQuery == null ||
o.NazwaMiejscaNaSwiecie.ToLower().Contains(searchQuery.ToLower()) ||
o.KrajMiejscaNaSwiecie.ToLower().Contains(searchQuery.ToLower()) ||
o.OpisMiejscaNaSwiecie.ToLower().Contains(searchQuery.ToLower()))).ToList();
var ViewModel = new HomeIndexViewModel()
{
MiejscaNaSwiecie = miejscaNaSwiecie
};
if (Request.IsAjaxRequest())
{
return PartialView("_ListaMiejsc", ViewModel);
}
return View(ViewModel);
}
Edited.

Because you are replacing the container. You should update only the content of that.
When you click for the first time, the response of the ajax call (the markup for the form) will replace the div (with id ="zawartosc"). So after this you do not have that div exist in your DOM any more. So your $targetElement is not going be the the container div (because it is gone !)
So instead of replacing the container div, simply update the content of that.
Replace
$($targetElement).replaceWith($newContent);
with
$($targetElement).html($newContent);

$($targetElement).html($newContent);
OR
$($targetElement).Load($newContent);

Related

How do I get cell values on click event from webpage tabs after the first one?

I have tried javascript and JQuery. I know how to write the code to get the cell values from my first tab but the same function does not work on the other tabs on my webpage. It seems as if the table in my other tabs is just a view. I am new to javascript and JQuery so think I might be missing something easy. I have used ".on" in my click function and that doesn't help. Here is the Javascript code and JQuery code, both work by grabbing the cell value I click but only for the first tab:
JavaScript
init();
function init(){
addRowHandlers('customerTable');
}
function addRowHandlers(tableId) {
if(document.getElementById(tableId)!=null){
var table = document.getElementById(tableId);
var rows = table.getElementsByTagName('tr');
var cid = '';
var name = '';
for ( var i = 1; i < rows.length; i++) {
rows[i].i = i;
rows[i].onclick = function() {
cid = table.rows[this.i].cells[0].innerHTML;
name = table.rows[this.i].cells[1].innerHTML;
alert('cid: '+cid+' name: '+name);
};
}
}
}
JQuery
$('#customerTable').find('tr').click(function() {
var $id = $(this).closest("tr")
.find(".custId")
.text();
var $name = $(this).closest("tr")
.find(".custName")
.text();
alert($name);
$('.defaultTextBox.text_custId:text').val($id);
$('.defaultTextBox.text_custName:text').val($name);
});
In the end my goal is to get the elements clicked and set the text in my text boxes to those values, which you can see I did in the JQuery, but it only works on my first page. I need the click in my table to work on all tabs. Thanks in advance!
Edit
<div id="removeCustomer" class="tabcontent">
<h3>Pick a customer to remove!</h3>
<div class="container">
<br />
<h2 align="center">Search here to find the customer you want to remove</h2><br />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">Search</span>
<input type="text" name="search_text" id="search_text" placeholder="Search by name, phone number, email, or state" class="form-control" />
</div>
</div>
<br />
<div class="result"></div>
</div>
</div>
The "removeCustomer" id is one of the tabs. So I have multiple tabs using the same, "result", which I think is the problem I just do not know how to solve it. If I Left out "result" it would not generate a table.
Here is the JQuery which uses a php file to connect to my database and get my data. And this is what generates result.
JQuery
$(document).ready(function(){
load_data();
function load_data(query)
{
$.ajax({
url:"fetchCustomers.php",
method:"POST",
data:{query:query},
success:function(data)
{
$('div.result').html(data);
}
});
}
$('input.form-control').keyup(function(){
var search = $(this).val();
if(search != '')
{
load_data(search);
}
else
{
load_data();
}
});
});
Thanks again.

MVC Core, How to retrieve the index of one of the List object

I am sorry for being unclear. Here's my code which I hope explain more
Controller:
[HttpPost]
public IActionResult Test(int classid)
{
return View();
}
View:
<form asp-action="Test">
#for (int i = 0; i < Model.Count(); i++)
{
var buttonid = "btnSubmit" + i;
#Html.TextBoxFor(model => Model[i].Name)
#Html.TextBoxFor(model => Model[i].ClassName)
<input name="submit" id="#buttonid" type="button" data-classid="#Model[i].ClassID" value="Go to class Form" class="btn btn-default MyButtonClass" style="font-size: 14px" />
}
<script>
$(document).on("click", ".MyButtonClass", function () {
var id = $(this).data("classid");
alert(id);
$.ajax({
type: "POST",
url: "/StudentController/Test",
data: { classid: id }
});
});
</script>
</form>
So what I wanted to do is when the user click the submit, it will redirect to another form which contain the className information (I know how to redirect to another page), however, the problem is that in another controller, I could only retrieve List and not the selected index className. Is there any method to retrieve the index when the user click submit?
Thanks
I've put an answer below which should hopefuly help you on your way.
First of all, build you your list of students in your controller.
public class TestController : Controller
{
public ActionResult Test()
{
var list = new List<Student>()
{
new Student()
{
Name = "Student1",
ClassID = 1,
ClassName = "ClassA"
},
new Student()
{
Name = "Student2",
ClassID = 2,
ClassName = "ClassB"
},
new Student()
{
Name = "Student3",
ClassID =3,
ClassName = "ClassC"
}
};
//You can call a service and populate your own data.
return View("Test", list);
}
}
Specify the views model
#model List<TestMVC.Student>
Then loop through each student, generating a unique id for each button and putting the classid (what ever key id you need) into the data-classid attribute.
#for (int i = 0; i < Model.Count(); i++)
{
var buttonid = "btnSubmit" + i;
#Html.TextBoxFor(model => Model[i].Name)
#Html.TextBoxFor(model => Model[i].ClassName)
<input name="submit" id="#buttonid" type="button" data-classid="#Model[i].ClassID" value="Go to class Form" class="btn btn-default MyButtonClass" style="font-size: 14px" />
<br/>
}
We also specify a new css class called "MyButton". This will serve the jquery selector.
<style>
.MyButtonClass {
color:red;
}
</style>
Then use Jquery to capture the button clicked, take off the id and post id as a parameter to which ever controller and action you want.
<script>
$(document).on("click", ".MyButtonClass", function () {
var id = $(this).data("classid");
alert(id);
$.ajax({
type: "POST",
url: "/YourController/YourAction",
data: {classid:id}
});
});
</script>
The line for "data". The "classid" must be the same name as the parameter on your controller. So the posted actions signature would be
[HttpPost]
public void YourAction (int classid)
{
}
Hope that helps.
Try this:
<div id="classList">
#for (int i = 0; i < Model.Count(); i++)
{
var buttonid = "btnSubmit" + i;
#Html.TextBoxFor(model => Model[i].Name)
#Html.TextBoxFor(model => Model[i].ClassName)
<button id="#buttonid" data-classid="#Model[i].ClassID" class="btn btn-default MyButtonClass">Go to class Form</butotn>
}
</div>
<script>
$(document).ready(function()
{
$(".MyButtonClass").on("click", function ()
{
var id = $(this).data("classid");
console.log(id);
$.ajax({
type: "POST",
url: "/StudentController/Test",
data: { classid: id },
success: function(data)
{
// put redirect in here
window.location = .....;
},
error: function()
{
// error handling
}
});
});
});//------- this was missing!!!!
</script>
In your controller:
[HttpPost]
public IActionResult Test(int classid)
{
// put debugger here so we know if we landed
return new { success=true};
}
You are using an ajax post so you probably just want data returned, not an entire view. Or do you? What exactly is supposed to happen when you get here?

ASP.NET MVC -Refresh CodeMirror editor onclick

I have a codemirror editor in a partial view and a list of files in the main view. I want to refresh the editor once a file name is clicked. I tried many solutions provided on StackOverflow and other websites but nothing worked , and This is my first time using Javascript so I can't figure out What am I doing wrong.
This is my code:
Controller:
public ActionResult Index()
{
StudentsCodes model = new StudentsCodes();
model.Student = (Student)CurrentUser;
var user = UserManager.FindById(((Student)CurrentUser).InstructorID);
model.Instructor =(Instructor) user;
return View(model);
}
public PartialViewResult DevelopmentPartial (StudentsCodes path )
{
return PartialView(path);
}
Main view:
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script type="text/javascript" src="~/Scripts/jquery-3.1.1.js"></script>
<ul id="tree">
#foreach (var file in Directory.GetFiles(Server.MapPath("~/Content/" + Model.Student.UserName + "/CompilerProject/" + name)))
{
var filename = Path.GetFileName(file);
<li id="filelist" onclick="#(Model.path = "~/Content/" + Model.Student.UserName + "/CompilerProject/src/" + #filename)">
<span class="glyphicon glyphicon-file"></span>
#filename
/li>
}
<div id="partial">
#{
Html.RenderPartial("DevelopmentPartial",null);
}
</div>
<script>
$(document).ready(function () {
$("#filelist").click(function (e) {
#{Html.RenderAction("DevelopmentPartial", Model);
}
});
});
</script>
partial view:
#using (Html.BeginForm())
{
var fileContents= "";
if (Model==null)
{
fileContents = "";
}
else
{
fileContents = System.IO.File.ReadAllText(Server.MapPath(Model.path));
}
#Html.TextArea("code", fileContents, new { id = "code" })
}
I can't assign ids for list elements since their number is unknown at compile time and it changes when the user adds or deletes a file, that's why most of the solutions provided didn't work . The result here was 3 editors overlapping and display the contents of the last file. And <li> items are non-clickable. What am I doing wrong in my code ?
Edit:
After updating the script as the following:
<script>
$(document).ready(function() {
$(".filelist").on("click",function (e) {
$("#partial").load('DevelopmentPartial');
});
});
</script>
It refreshes the partial view but the editor is always empty, and the Model is always null. Is it wrong to update the Model using "onclick"?
In case someone faced the same problem, I solved it by changing id to class at the list, then by using this script:
<div id="partial">
#{
Html.RenderAction("DevelopmentPartial", new { path1 = Model.path});
}
</div>
<script>
$(document).ready(function () {
$('.filelist').on('click', function (e) {
alert('Im clicked on filePath = ' + $(this).attr('value'));
var filePath = $(this).attr('value'); //value is attribute set in Html
$('#partial').load('DevelopmentPartial', { path1: filePath });
});
});
</script>
And the controller:
public PartialViewResult DevelopmentPartial(string path1)
{
modelSC.path = path1;
return PartialView(modelSC);
}
where modelSC is a global variable in the controller.

Form functionality lost in ng-if

I have a simple form with a checkbox which clicked deletes a property from an object.
Here is the controller:
app.controller('PropController', function ($scope) {
var str = '{"meta":{"aprop":"lprop"},"props":{"gprop":12,"lprop":9,"wrop":5}}';
$scope.filecontent = JSON.parse(str);
$scope.delprop = false;
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('delprop', function () {
if ($scope.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
And the view:
<div ng-app="SomeProperties" ng-controller="PropController">
<div ng-if="proptodel">
there is a property to delete: {{proptodel}}
<form><input type="checkbox" ng-model="delprop"></form>
filecontent: {{filecontent}}
</div>
<div ng-if="!proptodel">
there is NO property to delete
</div>
</div>
The app on jsfiddle.
The problem appears when the form is in the ng-if, it stops behaving. As you can try it in the jsfiddle, when I delete ng-if="proptodel" from the div containing the form, it working normally. What is the explanation of this?
You need to put the delprop into in object to make ng-model work properly. That means your markup should have:
<form><input type="checkbox" ng-model="obj.delprop"></form>
And your Javascript code should look like:
$scope.obj = {
delprop: false
};
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('obj.delprop', function () {
if ($scope.obj.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
Of course you should find a proper name for the object as obj is really bad and generic ;-)

How can I use an autosave partial view on a page with multiple forms?

Extending the example found at Autosave in MVC (ASP.NET), I wanted to create a partial to reuse in my application. I have one view with a tabbed layout, and each tab has its own form, and this is causing problems, namely that every form tries to submit every time, and only the first timestamp in the document updates. I understand why this is happening, but I don't know how I can fix it.
Partial's cshtml:
<div class="form-group">
<label class="control-label col-lg-2" for=""> </label>
<div class="col-lg-10">
<span class="help-block" id="autosaveTime">Not Autosaved</span>
</div>
</div>
#{
var autosaveString = "'" + #ViewData["autosaveController"] + "'";
if (ViewData["autosaveAction"] != null && ViewData["autosaveAction"] != "")
autosaveString += ", '" + ViewData["autosaveAction"] + "'";
}
<script type="text/javascript">
$(document).ready(function () {
autosave(#Html.Raw(autosaveString));
});
</script>
Javascript:
//methodName is optional-- will default to 'autosave'
function autosave(controllerName, methodName)
{
methodName = typeof methodName !== 'undefined' ? methodName : 'autosave'
var dirty = false;
$('input, textarea, select').keypress(function () {
dirty = true;
});
$('input, textarea, select').change(function () {
dirty = true;
});
window.setInterval(function () {
if (dirty == true) {
var form = $('form');
var data = form.serialize();
$.post('/' + controllerName + '/' + methodName, data, function () {
$('#autosaveTime').text("Autosaved at " + new Date);
})
.fail(function () {
$('#autosaveTime').text("There was a problem autosaving, check your internet connection and login status.");
});
dirty = false;
}
}, 30000); // 30 seconds
}
I have 2 ideas on how to fix it, but not sure which is more maintainable/workable:
Give each form an id, and pass that to the partial/autosave function. Add the name to the autosavetime text block for updates, and to determine which form to serialize/submit.
Somehow use jquery's closest function to find the form where the autosave block was placed, and use that to do what I was doing explicitly with #1.
First, make the URL using your Razor helper's Html extension (dynamically piecing URLs like this in JavaScript is unnecessarily risky). Take that, and stuff it in a data attribute on the tab control like so:
<div class="tab autosave" data-action-url='#Html.Action("Action", "Controller")'>
<form>
<!-- Insert content here -->
</form>
</div>
Then, you'll want something like this ONCE -- do not include it everywhere, and remove the javascript from your partial completely:
$(function() {
// Execute this only once, or you'll end up with multiple handlers... not good
$('.autosave').each(function() {
var $this = $(this),
$form = $this.find('form'),
dirty = false;
// Attach event handler to the tab, NOT the elements--more efficient, and it's always properly scoped
$this.on('change', 'input select textarea', function() {
dirty = true;
});
setInterval(function() {
if(dirty) {
// If your form is unobtrusive, you might be able to do something like: $form.trigger('submit'); instead of this ajax
$.ajax({
url : $this.data('action-url'),
data : $form.serialize()
}).success(function() {
alert("I'm awesome");
dirty = false;
});
}
}, 30 * 1000);
});
});

Categories

Resources