How to put kendo validator message span element underneath the input being validated? - asp.net-mvc

I'm trying to figure this out for a while.
All the examples I saw, use the html with input and span elements manually inserted
I have the following code that generate form and its datepicker elements dynamically:
#using (Html.BeginForm("Reload", "FileDate", FormMethod.Post, new { returnUrl = this.Request.RawUrl, id = "DateForm", onsubmit = "return ValidateDate();" } ))
{
#(Html.Kendo().DatePicker()
.Name("Date")
.Value(Session["FileDate"] == null ? DateTime.Now : Convert.ToDateTime(Session["FileDate"].ToString()))
.Events(e => e
.Change("datepicker_change")
)
)
#Html.Hidden("returnUrl", this.Request.RawUrl)
<script>
function datepicker_change() {
if(ValidateDate()){
$("#DateForm").submit();
}
}
</script>
}
When form is generated, I have the following code on the page:
This is a validation:
<script>
$(document).ready(function() {
$("#mainMenu").kendoMenu();
$("#Date").attr('required', 'required');
$("#Date").attr('data-WrongFormat-msg', 'Date Format is Wrong');
var validator = $("#container").kendoValidator({
rules: {
WrongFormat: function (input) {
if (input.is("[data-role=datepicker]")) {
var dateBox = input.data("kendoDatePicker");
return input.data("kendoDatePicker").value();
} else {
return true;
}
}
}
})
});
function ValidateDate()
{
var validator = $("#container").data("kendoValidator");
if (validator.validate()) {
return true;
}
else
{
return false;
}
}
</script>
When I provide the incorrect input or no input at all, I get the correct message in the span. However, this span section modifies the layout of the page:
How can I fix that, so my error span is placed underneath my form, the way it is shown in some examples like here: http://dojo.telerik.com/ikUfu:

I have the exact same issue. The problems seems to be that the validation message span element is in the wrong place for DatePickers. It is inside this element:
but, in all other widgets, it's inside the spam element one level higher:
So, it seems this is a bug in Telerik at the moment. It works for other widgets, but not for DatePicker. I'll see and find if this bug is already reported, and if not, report it. If you desperately need it fixed asap, I assume you could try some jquery magic to move the span element.

I've faced it too. Is there any proper solution for this issue?
My workaround in a nutshell:
Delete all possible old error messages
Move the new one into the proper HTML container
<div id="div_id">
<input id="input_id" type="text">
</div>
<script>
var validatable = $("[id='input_id'").kendoValidator({
rules: {
minimumLengthRule: function (input) {
var trimmedInputValue = $.trim(input.val());
return trimmedInputValue.length > 0 ;
}
},
messages: {
minimumLengthRule: "The input length is too short."
}
}).data("kendoValidator");
validatable.bind("validateInput", function (e) {
$("#div_id > span").not(':first').remove(); // 1.
if (!e.valid) {
$("[id='input_id_validationMessage'").appendTo('#div_id'); // 2.
}
});
</script>

Related

jQuery UI Autocomplete perform search on button click issues

I have a working UI Auto complete with jQuery. I wanted to change the way it worked. Instead of a new browser tab opening with the user selects a value from the list I wanted the user to first pick a value then click a search button to trigger the event.
It works but if you perform a search and then a second search it will trigger the previous URL and new URL at the same time. Also if you perform a search then click the search button without typing anything into the search input it triggers the previous search. Weird right? I'll add my code but I think a codepen example will help clarify what I mean.
The other issue I was having is I am trying to set up a custom alert if the value typed is not in the array but I get the invalid error message no matter what I type. I added that as well in the code. It is one of the if statements.
JS
var mySource = [
{
value: "Google",
url: "http://www.google.com"
},
{
value: "Yahoo",
url: "https://www.yahoo.com"
},
{
value: "Hotmail",
url: "https://hotmail.com"
},
{
value: "Reddit",
url: "https://www.reddit.com"
}
];
//Logic for ui-autocomplete
$(document).ready(function() {
$("input.autocomplete").autocomplete({
minLength: 2,
source: function(req, resp) {
var q = req.term;
var myResponse = [];
$.each(mySource, function(key, item) {
if (item.value.toLowerCase().indexOf(q) === 0) {
myResponse.push(item);
}
if (item.value.toUpperCase().indexOf(q) === 0) {
myResponse.push(item);
}
//Add if statement here to determine if what the user inputs is in the
// array
//and if not in the array give an error to #textAlert.
//Example
if (item.value.indexOf(q) != myResponse) {
$('#alertText').text("Invalid Search");
} else {
return false;
}
});
resp(myResponse);
},
select: function(event, ui) {
$('#appSearchBtn').one("click", function() {
window.open(ui.item.url);
$('#appsearch').val('');
return false;
});
}
});
});
//Input and ui text clears when clicked into
$(document).ready(function() {
var input = document.querySelector('#appsearch');
var ui = document.querySelector(".ui-helper-hidden-accessible");
input.onclick = function() {
input.value = '';
ui.textContent = '';
};
});
HTML
<p id="alertText"></p>
<div class="input-group">
<input type="text" id="appsearch" class="form-control autocomplete" placeholder="Application Search" />
<span class="input-group-btn">
<button class="btn btn-primary inputBtn" id="appSearchBtn" type="button">Search</button>
</span>
</div>
Here is a Code pen https://codepen.io/FrontN_Dev/pen/MEmMRz so you can see how it works. I also added how it should work and what the bugs are.
9/29/17 #0732
I resolved the issue with the event firing the same URL over and over but I still need help with the custom invalid search message that appears for every search even if the value is in the array.

How to get nicEdit textarea content in ng-model?

I'm new in Angular and html development. So i don't know yet all features and code terms.
I created a form which contains a rich textarea field. I used nicEdit as this is the one recommended by mycompany (so cannot change of editor).
As you can see in the image below, nicEdit is working well.
But when I want to get the field content in ng-model, it doesn't work.
Most of forum Q&A informs that that ng-model does not working properly with that nicEdit textarea. I found something about a directive to create. So I tried by modifying one dedicated to ckEditor.
But it doesn't work. I found that $('div.nicEdit-main') was the div updated (but not my field htmlLondDesc attached to the nicEdit textarea, neither the ng-model).
I also found something about the nicEditors.findEditor('htmlLongDesc').getContent(); but i don't know where to use it in the ng-model...
So how to get the content of nicEdit and save it in ng-model ?
Thanks in advance for your help.
Here is an image of the text area
Here is my js and html code:
scApp.directive('ncGetContent', function () {
return {
require: 'ngModel',
link: function (scope, elm, attr, ngModel) {
var content = $('div.nicEdit-main').html();
if (!ngModel) return;
content.on('instanceReady', function () {
content.setData(ngModel.$viewValue);
});
function updateModel() {
scope.$apply(function () {
ngModel.$setViewValue(content.getData());
});
}
content.on('change', updateModel);
content.on('key', updateModel);
content.on('dataReady', updateModel);
ngModel.$render = function (value) {
content.setData(ngModel.$viewValue);
};
}
};
});
<head>
<script type="text/javascript">
bkLib.onDomLoaded(function() {
var myEditor = new nicEditor({buttonList : ['bold','italic','underline','subscript','superscript','forecolor','bgcolor']}).panelInstance('htmlLongDesc');
var nicInstance = nicEditors.findEditor('htmlLongDesc');
});
</script>
</head>
...
<textarea id="htmlLongDesc" cols="140" rows="6" name="htmlLongDesc" ng-model="user.htmlLongDesc" ncGetContent ></textarea>

Knockout Binding Not Working with jQueryUI Dialogue

My viewModel has an array called 'Items'. I want to display the contents of 'Items' using a foreach binding. Everything works fine when I use regular HTML. But does not work with a dialogue box which I created using jQueryUI.
HTML:
<div id="skus0">
<div id="skus1">
<ul data-bind="foreach: Items">
<li data-bind="text:Name"></li>
</ul>
</div>
<input type="button" id="openQryItems" class="btn btn-info" value="Open" data-bind="click:openQueryItems" />
</div>
JavaScript:
// my view model
var viewModel = {
Items: [{Name:'Soap'},{Name:'Toothpaste'}]
};
// JS to configure dialogue
$("#skus1").dialog({
autoOpen: false,
width: 500,
modal: true,
buttons: {
"OK": function () {
$(this).dialog("close");
},
"Cancel": function () {
$(this).dialog("close");
}
}
});
// for mapping my model using ko.mapping plugin
var zub = zub || {};
zub.initModel = function (model) {
zub.cycleCountModel = ko.mapping.fromJS(model);
zub.cycleCountModel.openQueryItems = function () {
$("#skus1").dialog("open");
}
ko.applyBindings(zub.cycleCountModel, $("#skus0")[0]);
}
zub.initModel(viewModel);
I have created a fiddle here my fiddle
$.fn.dialog removes the element from its place in the DOM and places it in a new container; this is how it can create a floating window. The problem with this happening is that it breaks data binding, since the dialog DOM is no-longer nested within the top-level data-bound DOM.
Moving the dialog initialization to after ko.applyBindings will enable dialog to yank stuff out of the DOM after the list is populated. Of course, this means that after that point, future changes will still not be reflected, which may be important if you're wanting the opened dialog to change automatically.
If you are wanting the dialog contents to be fully dynamic, you could create a binding handler; we did this in our project. Here's a rough outline of how we did this:
ko.bindingHandlers.dialog = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingCtx) {
var bindingValues = valueAccessor();
var hasAppliedBindings = false;
var elem = $(element);
var options = {
id: ko.utils.unwrapObservable(bindingValues.id),
title: ko.utils.unwrapObservable(bindingValues.title),
// etc...
onOpen: function () {
if (!hasAppliedBindings) {
hasAppliedBindings = true;
var childCtx = bindingCtx.createChildContext(viewModel);
ko.applyBindingsToDescendants(childCtx, element);
}
}
};
elem.dialog(options);
}
return { controlsDescendantBindings: true };
}
...which we used like this:
<div data-bind="dialog: { title: 'some title', id: 'foo', ... }">
<!-- dialog contents -->
</div>
What return { controlsDescendantBindings: true } does is makes sure that outer bindings do not affect anything using the dialog binding handler. Then we create our own Knockout binding "island" after it is pulled out of the DOM, based on the original view model.
Although in our project we also used hybrid jQuery+Knockout, I would highly recommend you avoid this whenever possible. There were so many hacks we had to employ to sustain this type of application. The very best thing you should do is prefer Knockout binding handlers (and I think it has a "component" concept now which I haven't played with) over DOM manipulations to avoid buggy UI management.

MVC5 Partial View Example

I am seeking to create a reusable "employee lookup" control.
Note:I am assuming that a partial view is the best way to go.
I want multiple buttons on the page
Each button will call a PartialView and each button will have a specific textbox
Each partial will contain multiple Results (items)
On clicking one of the results I want to populate the button's textbox, that made the call, with the result
How am i able to do this, since the page will have multiple buttons and textboxes?
This control needs to be able to be called by multiple buttons
So, those buttons call an action which will render the partial which has those results?
I'm seeing multiple ways to do this. The easiest way is:
<button id="btn1" class="btns" data-target="txt1" type="button">A</button>
<button id="btn2" class="btns" data-target="txt2" type="button">B</button>
<input type="text" id="txt1" />
<input type="text" id="txt2" />
<div id="render">
</div>
<script>
var ajaxActive = false;
$(function() {
$(".btns").on('click', function () { // Bind the onclick of the button, so any button with this class may call the following function
var _button = $(this);
getItems(_button);
});
});
function getItems(_button) {
var bind = function (_button, results) {
$("#render").empty();
$("#render").append(results); // Append the partialview to the current view's div
$("#render .itemResult").on('click', function () { // Bind the onclick of the result
var resultValue = $(this).text(); // Or any other value that come from the result
var targetId = "#" + _button.data('target'); // Id of the input (Target) which comes from the clicked button
$(targetId).val(resultValue); // Change the input target value with the result one
});
};
if (ajaxActive) {
$.get('/Controller/Action') // Get the partialview
.done(function (results) {
bind(_button, results);
});
}
else {
var results = simulateCall(); // Get the results
bind(_button, results);
}
}
function simulateCall() { // Simulate a call to the server
return "<div class='items'> <div class='itemResult'>ABC</div> <div class='itemResult'>DEF</div> </div>";
}
</script>
PS: Here is a working demo
Keep in mind that i placed some sort of "call" to simulate it going to the database

How to validate select with JQuery.Validate while using JQueryMobile

I'm just exploring the Validate plug-in for JQuery. During implementing in my webapp made with JQueryMobile I stumbled over the fact that validating such an element is not so simple like usual input-elements.
So the Question is: How to enable validation for select?
The trick consists out of two parts:
Validate is by default ignoring :hidden. But that's what JQM does with an <select>: hide it and placing a div-span-wrapper on top. Solution is to redefine the ignore-selector:
{ignore: ":hidden:not(select)"}
To inform the user about the invalid field you have to show the error right on the wrapper:
$(error.element).closest('.ui-select').attr("title", error.message).addClass("invalidInput")
And now in an working example:
$.validator.setDefaults({
debug: true,
ignore: ":hidden:not(select)",
submitHandler: function() { alert("submitted!"); },
showErrors: function(map, list) {
$(this.currentElements).each(function() {
if(this.nodeName == "SELECT") {
$(this).closest('.ui-select').removeAttr("title").removeClass("invalidInput");
return true;
}
$(this).removeAttr("title").removeClass("invalidInput");
});
$.each(list, function(index, error) {
if(error.element.nodeName == "SELECT") {
$(error.element).closest('.ui-select').attr("title", error.message).addClass("invalidInput");
return true;
}
$(error.element).attr("title", error.message).addClass("invalidInput");
});
}
});
$('div[data-role="page"]').bind('pageinit', function(event) {
var rules = {};
$('input:not(:button)').each(function() {
rules[this.name] = {required:true};
});
$('#fzgherst').each(function() {
// revalidates the select when changed, other elements gets revalidatet onblur
$(this).on('change', function() {$(this).valid();});
rules[this.name] = {required:true};
});
$("form").validate({
rules: rules
});
});
That's all folks!

Resources