Why won't JS / JQuery read the text box values? - javascript

I have looked all over for a reason behind why this code does not work and I am stumped.
I have an ASPX page with C# code behind. The HTML mark-up has a JQuery dialog that functions properly. When the submit button is clicked the dialog closes and the data is passed to a web exposed method and is written to the database. All values are saved for the ddl and chkbox controls but the string value of the text box is empty. The database is set to NOT NULL for the field the text box is populating and the data is being saved so I know data is being passed but it is not the value entered into the text box.
The text box ID is txtCategoryName and the Client ID mode is set to static. I have tried to get the values using the following:
var CategoryName = $('#txtCategoryName').val();
var CategoryName = $('#txtCategoryName').text();
var CategoryName = $(document.getElementById('txtCategoryName')).text();
var CategoryName = $(document.getElementById('txtCategoryName')).val();
var CategoryName = document.getElementById('txtCategoryName').value;
All of these return the same blank field. I tried them one at a time.
Currently I am using this JS Code:
$(document).ready(function () {
var CategoryDialog = $(".EditCategories");
var BtnNew = $("#btnNew");
var CatDDL = document.getElementById("ddlCategoryParent3");
var CatChk = $("#chkCatActive").val();
var CategoryID = 0;
var CategoryName = $("#txtCategoryName").val();
var ParentID = CatDDL.options[CatDDL.selectedIndex].value;
if (CatChk) { CatChk = 1; } else { CatChk = 0; }
var CatDialog = $(CategoryDialog.dialog({
maxHeight: 1000,
closeOnEscape: true,
scrollable: false,
width: 650,
title: 'Category Editor',
autoOpen: false,
buttons: [
{
width: 170,
text: "Save",
icons: {
primary: "ui-icon-disk"
},
click: function () {
$(this).dialog("close");
window.alert(PageMethods.saveCat(CategoryName, ParentID, CategoryID, CatChk));
}
},
{
width: 170,
text: "Delete",
icons: {
primary: "ui-icon-circle-minus"
},
click: function () {
$(this).dialog("close");
}
},
{
width: 170,
text: "Cancel",
icons: {
primary: "ui-icon-circle-close"
},
click: function () {
$(this).dialog("close");
}
}
]
})
);
BtnNew.click(function () {
$(CatDialog).dialog('open');
$(CatDialog).parent().appendTo($("form:first"));
});
});
The code markup for the aspx page (categories.aspx)
<div class="EditCategories">
<div class="Table">
<div class="TableRow">
<div class="TableCell">
<div class="TextBlock220">Category Name </div>
</div><!-- End Table Cell -->
<div class="TableCell">
<input id="txtCategoryName" class="ControlTextBox" />
<!--<asp:TextBox ID="txtCategoryName" CssClass="ControlTextBox" runat="server" ClientIDMode="Static"></asp:TextBox>-->
</div><!--End Table Cell-->
</div><!-- End Row 1 -->
<div class="TableRow">
<div class="TableCell">
Parent Category
</div><!-- End Table Cell -->
<div class="TableCell">
<asp:DropDownList ID="ddlCategoryParent3" runat="server" CssClass="ControlDropDownList" ClientIDMode="Static"></asp:DropDownList>
</div><!--End Table Cell-->
</div>
<div class="TableRow">
<div class="TableCell">
Active
</div><!-- End Table Cell -->
<div class="TableCell">
<asp:Checkbox ID="chkCatActive" CssClass="ControlCheckBox" runat="server" ClientIDMode="Static"></asp:Checkbox>
</div><!--End Table Cell-->
</div><!-- End Row 3-->
</div>
</div>
The C# Code behind method for the ASPX page:
[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static string saveCat(string _Name_, int _parent_id_, int ID, int _Status_)
{
Category eCT = new Category();
eCT.CategoryName = _Name_;
eCT.ParentID = _parent_id_;
eCT.ID = ID;
eCT.Status = _Status_;
eCT.Save();
return eCT.resultMessage;
}
And the save method:
/// <summary>
/// If the ID = 0 the data is written as a new category.
/// If the ID is greater than 0 the data is updated.
/// </summary>
/// <returns>The objects result value will hold the result of the attempt to update data as type Boolean. The objects resultMessage value will contain the string result of the attempt to add data.</returns>
public void Save()
{
result = dl.CategoryExists(this);
if (result) { resultMessage = "The parent category already contains a category named " + CategoryName.Trim(); }
else {
if (ID > 0)
{
if (!result) { resultMessage = "There was an unexpected error updating " + CategoryName.Trim() + ". No changes were saved."; }
}
else
{
result = dl.InsertCategory(this);
if (!result) { resultMessage = "There was an unexpected error creating the Category."; }
}
}
if (result) { resultMessage = "New Category Successfully Created"; }
}
Any help is greatly appreciated thanks.

The issue here is you're attempting to get the value right as soon as the page loads, before the input field gets filled out. Place this code inside the button click function:
var CategoryName = document.getElementById('txtCategoryName').value;
and it should work for you. If not, let us know.
Your code should look something like this:
click: function () {
// note: CategoryID not used yet.
var CategoryName = $("#txtCategoryName").val();
var CatChk = $("#chkCatActive").val();
var CatDDL = document.getElementById("ddlCategoryParent3")
var ParentID = CatDDL.options[CatDDL.selectedIndex].value;
if (CatChk) { CatChk = 1; } else { CatChk = 0; }
$(this).dialog("close");
window.alert(PageMethods.saveCat(CategoryName, ParentID, CategoryID, CatChk));
}

You are fetching the values from your dialog at page startup time BEFORE they have been edited.
It looks like this:
var CategoryName = $("#txtCategoryName").val();
is run at page startup time before the page has been edited. This will fetch the default value for the input field and will never reflect any editing that is done on the page. The line of code above does not create a "live" connection with the input field on the page. It just gets the value at the time that line of code is run and from then on there is no connection to any edits made to the field.
I would think you want to fetch the value only later when you actually need to value for something. In general, you do not want to cache a value like this because the cached value gets out of sync with what is in the actual field on the page. Just fetch it at the very moment that you need it for something and it will never have a stale value.
If the place that you're using this value is inside the dialog click handler, then fetch it there so you are getting the latest value:
click: function () {
$(this).dialog("close");
var CatChk = $("#chkCatActive").val() ? 1 : 0;
var CategoryName = $("#txtCategoryName").val();
var CatDDL = document.getElementById("ddlCategoryParent3");
var ParentID = CatDDL.options[CatDDL.selectedIndex].value;
window.alert(PageMethods.saveCat(categoryName, ParentID, CategoryID, CatChk));
}

Related

Ajax search doesn't work the second time (ASP.NET MVC)

I have a problem changing items after searching.
I looked at similar threads but found no solution there :(
It looks like the first time the page loads well - the first time the entire Index.cshtml page is loaded which contains a collection of books in the selected category.
There is a search engine on the page - after searching for "manual" - ajax correctly replaces elements with those containing "manual" in the name.
Then when I enter something into the search engine a second time (for example "exercises") - the content of the page does not change any more.
I tried to debug and I see that new items are correctly downloaded from the database - the condition "if (Request.IsAjaxRequest ())" is true and the items are passed to partial view - there the "foreach" loop goes through them. Unfortunately, after _Partial, nothing happens.
I can't find a mistake - the strangest thing is that the first ajax call works fine - only the second (and subsequent) bad.
CatalogController.cs
public ActionResult Index(string categoryName = null, string searchQuery = null)
{
if (categoryName == null)
categoryName = (db.Categories.Find(1)).Name;
var category = db.Categories.Include("Books").Where(x => x.Name.ToLower() == categoryName).Single();
var books = category.Books.Where(x => (searchQuery == null || x.Title.ToLower().Contains(searchQuery.ToLower()) || x.SubTitle.ToLower().Contains(searchQuery.ToLower()) || x.Level.ToLower().Contains(searchQuery.ToLower())) && !x.Inaccessible);
if (Request.IsAjaxRequest())
return PartialView("_PartialBooksList", books);
else
return View(books);
}
Index.cshtml
<form class="o-search-form" id="search-form" method="get" data-ajax="true" data-ajax-target="#booksList">
<input class="o-search-input" id="search-filter" type="search" name="searchQuery" data-autocomplete-source="#Url.Action("SearchTips")" placeholder="Search" />
<input class="o-search-submit" type="submit" value="" />
</form>
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
#section Scripts
{
<script src="~/Scripts/jquery-3.5.0.js"></script>
<script src="~/Scripts/jquery-ui-1.12.1.js"></script>
<script>
$(function () {
var setupAutoComplete = function () {
var $input = $(this);
var options =
{
source: $input.attr("data-autocomplete-source"),
select: function (event, ui) {
$input = $(this);
$input.val(ui.item.label);
var $form = $input.parents("form:first");
$form.submit();
}
};
$input.autocomplete(options);
};
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-filter").each(setupAutoComplete);
$("#search-form").submit(ajaxSubmit);
});
</script>
}
_PartialBooksList
#model IEnumerable<ImpressDev.Models.Book>
#using ImpressDev.Infrastructure
<div class="row">
#foreach (var book in Model)
{
<div class="col-12 col-xl-4">
<a class="o-shop-link" href="#Url.Action("Details", "Catalog", new { bookId = book.BookId })">
<div class="o-shop-item">
<img class="o-shop-img" src="#Url.BookPhotoSourcePath(book.PhotoSource)" />
<div class="o-shop-text">
<h2>#book.Title</h2>
<h6>#book.SubTitle - #book.Level - <b>#book.Price zł.</b></h6>
+ Add to cart
</div>
</div>
</a>
</div>
}
</div>
Please help
I am not sure if this is the case, but try to change this code:
$($targetElement).replaceWith($newContent);
To this:
$($targetElement).html($newContent);
I think the problem is the div element with id="booksList" is replaced after first search. So you don't have this element in the second search.
I looked through the code step by step and found a solution to my problem.
In the first search, replace id="booksList"
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
partial view in which there was only without id = booksLists.
In the next search there was no ID in this place and there was nothing to replace.

Implementing a Modal Factory?

I'be been using modals as a means to communicate to users in my apps for some time now via several different front end frameworks. The logic is usually the same, defining the modal's html then rendering it via some click event.
As my applications grow, so do the number of modals I use for a user prompt or confirmation - these modals can have anything from text inputs to forms to dropdowns and so on.
My current method is to write out each separate modal in a single html file and simply call them by their IDs but I feel this is inefficient as there is plenty of duplicate boilerplate code, so I'm wondering the best way would be to create modals dynamically while keeping the code as light andclean as possible?
I've been thinking of something like a "modal factory" where you pass the content of the modal along with the height, width, styling, etc. would this be a good approach?
Thanks for any input!
Well what I do for Forms/HTML Content loaded from the server - is create a div with an ID - PartialViewDialog at the end of my page -(I load Partial Views inside a Dialog)
This one is Bootstrap 3.* based - (HTML structure based on Frontend framework
So the HTML is like this:
<body>
<!-- Other page content -->
<div class="modal fade" id="PartialViewDialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" data-modal="title"></h4>
</div>
<div class="modal-body" data-modal="content">
</div>
<div class="modal-footer" data-modal="footer">
</div>
</div>
</div>
</div>
</body>
Then in JS, I create a dialog Manager:
var MyApp = MyApp || {};
MyApp.UIHelper = MyApp.UIHelper || {};
MyApp.UIHelper.DialogManager = (function () {
"use strict";
var self = {};
self.divId = null;
self.dialog = null;
self.dialogBody = null;
self.dialogTitle = null;
self.dialogFooter = null;
self.actionUrl = "";
self.modalObject = null;
self.options = {};
function Initilize(divId, options) {
self.options = $.extend({ buttons: [] }, options);
self.divId = divId;
self.dialog = $(self.divId);
self.dialogBody = self.dialog.find('*[data-modal="content"]');
self.dialogTitle = self.dialog.find('*[data-modal="title"]');
self.dialogFooter = self.dialog.find('*[data-modal="footer"]');
self.BootgridObject = null;
};
function OpenPartialViewDialog(url, title, preprocessingFunction, postProcessingFunction) {
// Create the buttons
var options = self.GetPartialViewButtons(url, preprocessingFunction, postProcessingFunction);
// Initialise the PartialViewDialog with Buttons
Initilize('#PartialViewDialog', options);
// Set the URL for Ajax content load and Form Post
self.actionUrl = url;
// Set Dialog Title
self.dialogTitle.html(title);
// Open the PartialViewDialog
self.OpenModel();
};
// This Method creates the buttons for the Form dialog
// e.g Save, Cancel, Ok buttons
self.GetPartialViewButtons = function (url, preprocessingFunction, postProcessingFunction) {
// I only need Save and Cancel buttons always so I create them here
var buttons = {
buttons: {
// I create a save button which Posts back the Form in the Dialog
Save: {
Text: "Save",
css: "btn btn-success",
click: function () {
// Call a function before sending the Ajax request to submit form
if (preprocessingFunction) { preprocessingFunction(); }
$.ajax({
type: "POST",
url: url,
// This Dialog has a Form - which is Post back to server
data: self.dialogBody.find("form").serialize(),
success: function (response) {
// TODO: Check if response is success -
// Apply your own logic here
if (response.hasOwnProperty("IsSuccess")) {
if (response.IsSuccess) {
self.dialogBody.html("");
self.dialog.modal("hide");
// TODO: Show Success Message
// You can call another function if you want
if (postProcessingFunction) {
postProcessingFunction();
}
} else {
// If failure show Error Message
}
}
},
error: function (response) {
// If failure show Error Message
}
});
}
},
Cancel: {
Text: "Cancel",
css: "btn btn-danger",
click: function () {
self.dialogBody.html("");
self.dialogFooter.html("");
self.dialogTitle.html("");
self.dialog.modal("hide");
}
}
}
};
return buttons;
};
// dynamic creating the button objects
self.CreateButtonsHtml = function () {
var htmlButtons = [];
$.each(self.options.buttons, function (name, props) {
var tempBtn = $("<button/>", {
text: props.Text,
id: "btn_" + props.Text,
"class": props.css + "",
click: props.click
}).attr({ "style": "margin-right: 5px;" });
htmlButtons.push(tempBtn);
});
return htmlButtons;
};
// This method will load the content/form from server and assign the modal body - it will assign the buttons to the Modal Footer and Open the Dialog for user
self.OpenModel = function () {
$.ajax({
url: self.actionUrl,
type: "GET",
success: function (response) {
// Handle response from server -
// I send JSON object if there is Error in loading the content - otherwise the result is HTML
if (response.hasOwnProperty("HasErrors")) {
// Means some error has occured loading the content - you will have to apply your own logic
} else {
//Server return HTML - assign to the modal body HTML
self.dialogBody.html(response);
self.modalObject = self.dialog.modal();
// show modal
self.modalObject.show();
}
}
});
// Create the buttons in the Dialog footer
var buttons = self.CreateButtonsHtml();
self.dialogFooter.html('');
for (var i = 0; i < buttons.length; i++) {
self.dialogFooter.append(buttons[i]);
}
};
return {
OpenPartialViewDialog: OpenPartialViewDialog,
};
})();
Then whenever I need to open a dialog from the server I can call it like this:
MyApp.UIHelper.DialogManager
.OpenPartialViewDialog('/Content/Load', "My Title",
function(){alert('pre-process')},
function(){alert('post-process')}
);
Note: The PreProcess + PostProcess are called when the Save button is clicked
Here is a working/demo example which shows what the above JS does - Hope it helps
In the demo I load Dummy HTML from a div id="dummycontent"
Fiddle: https://jsfiddle.net/1L0eLazf/
Button Fiddle: https://jsfiddle.net/1L0eLazf/1/

How to marked checkbox in function jquery

I have a listbox in view.
This Listbox use template
Listbox
<div id="UsersLoad" style="width: 50%">
#Html.EditorFor(i => i.Users, "UsersForEdit")
</div>
Template UserForEdit (Part of the code)
#model string[]
#{
if (this.Model != null && this.Model.Length > 0)
{
foreach(var item in this.Model)
{
listValues.Add(new SelectListItem { Selected = true, Value = item, Text = item });
}
}
else
{
listValues = new List<SelectListItem>();
}
}
<div class="field-#size #css">
<h3>#Html.LabelFor(model => model):</h3>
#Html.ListBoxFor(model => model, listValues, new { id = id })
</div>
In another view div "Users" is called.
function LoadUsersCheckBox() {
$("#UsersLoad").load('#Url.Action("LoadUsers", "User")' + '?idUser=' + idUser);
}
LoadUsers Controller
public JsonResult LoadUsers(int? idUser)
{
var users = Service.GetSystemUsers(idUser);
var model = users.Select(x => new
{
Value = x,
Description = x
});
return this.Json(model, JsonRequestBehavior.AllowGet);
}
The controller method returns what I want.
But instead of it select the items in the listbox it overwrites the listbox with only the text of found users.
How to mark the items in the listbox on the function LoadUsersCheckBox?
Sorry for my bad English
The jQuery load() method "loads data from the server and places the returned HTML into the matched element." Note the words "the returned HTML". See http://api.jquery.com/load/
To select existing items, you should try get() instead (http://api.jquery.com/jQuery.get/). In the success callback handler, you will need to parse the returned data to an array. Then use an iterator to go over the items in the listbox, and if they exist in the parsed array, mark them as selected. Something like:
$.get("action url", function(data) {
var users = $.parseJSON(data);
$("#UsersLoad option").each(function() {
var opt = $(this),
value = opt.attr("value");
opt.removeAttr("selected");
if (users.indexOf(value) > -1) {
opt.attr("selected", "selected");
}
});
});

Images in JSON AngularJS

I'm new to AngularJS, so sometimes when I do some mistake that is obvious, I still can't figure out what is going wrong with my code. So saying, here is my doubt:
HTML code:
<body ng-controller = "Ctrl">
<script id="Page6.html" type="text/ng-template">
<div class="list card" style="background-color: beige">
<div class="item item-icon-left">
<i class="icon ion-home"></i>
<input type="text" placeholder = "Enter display name" ng-model="user.nam">
</div>
<a ng-click = "saveedit(user)"<button class="button button-clear">SAVE DETAILS</button></a>
</div>
</script>
</body>
CONTROLLER.JS
.controller('Ctrl',function($scope,$rootScope,ContactService){
$rootScope.saveedit=function(user) {
ContactService.save({names: user.nam, image:"images.jpg"},ContactService.getid("Donkey"));
}
});
THIS IS THE SERVICE:
.service('ContactService', function () {
var items = [
{ id: 1, names: 'Dolphin', image: 'dolphin.jpg',}, { id: 2, names: 'Donkey', image: 'donkey.jpg'}, { id: 3, empid: 'FG2043', image: 'penguin.jpg'}];
var im = [{image: ''}];
var ctr=0;
var uid=3;
this.save = function (contact,id) {
ctr=0;
for (i=0;i<items.length;i++) {
if(items[i].id == id)
{
im[0].image= items[i].image;
ctr=100;
break;
}
}
uid = (uid+1);
contact.id = uid;
items.push(contact);
if (ctr==100 ) {
alert("in save putting the image");
items[contact.id].image = im[0].image; //doubt
alert("finished putting image");
}
}
//simply search items list for given id
//and returns the object if found
this.getid = function (name) {
for (i=0;i<items.length;i++) {
if (items[i].names == name) {
return (i+1);
}
}
}
//simply returns the items list
this.list = function () {
return items;
}
});
The problem I am facing is this: Everything works, except one thing. In ContactService, push() function, the line I have commented as //doubt is not getting executed.
The alert before it "in save putting the image" runs, but the alert "finished putting image" doesn't. What is the mistake there??
The problem here is that you're using the id's, which start at 1, to navigate in an array whose indexes start at 0.
To access the most recently pushed element, you should rather do :
items[contact.id - 1].image = im[0].image;
But you actually don't need to access the array : items[contact.id - 1] will return the object that you just pushed, and which is already referenced by variable contact, so you could just do :
contact.image = im[0].image;

DropDownList Change() doesn't seem to fire

So, I have been bashing my head against the desk for a day now. I know this may be a simple question, but the answer is eluding me. Help?
I have a DropDownList on a modal that is built from a partial view. I need to handle the .Change() on the DropDownList, pass the selected text from the DropDownList to a method in the controller that will then give me data to use in a ListBox. Below are the code snippets that my research led me to.
all other controls on the modal function perfectly.
Can anyone see where I am going wrong or maybe point me in the right direction?
ProcessController
// I have tried with [HttpGet], [HttpPost], and no attribute
public ActionResult RegionFilter(string regionName)
{
// Breakpoint here is never hit
var data = new List<object>();
var result = new JsonResult();
var vm = new PropertyModel();
vm.getProperties();
var propFilter = (from p in vm.Properties
where p.Region == regionName && p.Class == "Comparable"
select p).ToList();
var listItems = propFilter.ToDictionary(prop => prop.Id, prop => prop.Name);
data.Add(listItems);
result.Data = data;
return result;
}
Razor View
#section scripts{
#Scripts.Render("~/Scripts/ui_PropertyList.js")
}
...
<div id="wrapper1">
#using (Html.BeginForm())
{
...
<div id="fancyboxproperties" class="content">
#Html.Partial("PropertyList", Model)
</div>
...
<input type="submit" name="bt_Submit" value="#ViewBag.Title" class="button" />
}
</div>
Razor (Partial View "PropertyList.cshtml")
...
#{ var regions = (from r in Model.Properties
select r.Region).Distinct(); }
<div>
<label>Region Filter: </label>
<select id="ddl_Region" name="ddl_Region">
#foreach (var region in regions)
{
<option value=#region>#region</option>
}
</select>
</div>
// ListBox that needs to update after region is selected
<div>
#Html.ListBoxFor(x => x.Properties, Model.Properties.Where(p => p.Class == "Comparable")
.Select(p => new SelectListItem { Text = p.Name, Value = p.Id }),
new { Multiple = "multiple", Id = "lb_C" })
</div>
...
JavaScript (ui_PropertyList.js)
$(function () {
// other events that work perfectly
...
$("#ddl_Region").change(function () {
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").attr("text"), updateProperties(data));
});
});
function updateProperties(data, status) {
$("#lb_C").html("");
for (var d in data) {
var addOption = new Option(data[d].Value, data[d].Name);
addOption.appendTo("#lb_C");
}
}
The callback function passed to your $.getJSON method is wrong. You need to pass a reference to the function, not to invoke it.
Try this:
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").text(), updateProperties);
Also, in order to get the text of the selected drop-down option, you need to use the text() function:
$("#ddl_Region > option:selected").text()
See Documentation

Categories