knockout not working in MVC4 project - asp.net-mvc-3

I have the following in my Index.cshtml file (from the knockout site):
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
<script type="text/javascript">
// Here's my data model
var ViewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work
</script>
My Layout has this line:
#Scripts.Render("~/bundles/knockout")
Which is configured correctly in bundler config:
bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
"~/Scripts/Libraries/knockout-2.2.1.js"));
Chrome sees the file and VS is giving me intellisense, so I'm not sure what's going on. None of the knockout functions are working.
I tested this outside of MVC (just using html/css) and it worked fine. Any idea what's going on?
EDIT: I tried using a direct reference without bundler and it still doesn't work:
<script type="text/javascript" src="~/Scripts/Libraries/knockout-2.2.1.js"></script>
I'm getting an error from chrome:
Uncaught ReferenceError: ko is not defined

Could you post some JS console error from chrome or firebug? Looks like a missing reference from knockout.
EDIT: Put your script at the end of its view! Another thing, the reference for knockout must stay below the reference for jquery, because its dependent.
EDIT:
Register the knockout
bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
"~/Scripts/knockout-{version}.js"));
Render It in your view
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/knockout")

Include your javascript code in a JS file and render this after knockout
Like this:
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/MYSCRIPTS")

I fixed my issue by removing my script line at the end of my Index.cshtml file:
<script src="~/Scripts/ConfigGroup.js"></script>
and replacing it with:
#section Scripts {
#Scripts.Render("~/Scripts/ConfigGroup.js")
}
I guess section Scripts gets loaded at a different time than includes.

Related

Ajax html response to div

Hi I am printing the ajax html response to div element and giving radio input option to select the file. after selecting the specific file the another div should show the message. but the ajax html response is not working
Jquery script:
$(document).ready(function()
{
$('#upload').ajaxForm({
beforeSubmit: function() {
$('#Analysis').show();
$('#Content_column').hide();
$('#file_list').show();
$('#trait').show();
$('#trait').html('Submitting...');
},
success: function(data) {
var $out = $('#file_list');
$out.html('&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspFile list:');
$out.append('<div id="list">');
$('#list').html(data);
$out.append('</div>');
}
});
});
The output of this script is
<ul class="php-file-tree"><li class="pft-directory">Genotypic<ul><input id="Penotypic" type="radio" name="uploads/Genotypic/" value="uploads/Genotypic/jquery.txt" />jquery.txt<br><input id="Penotypic" type="radio" name="uploads/Genotypic/" value="uploads/Genotypic/marker.csv" />marker.csv<br></ul></li><li class="pft-directory">Other</li><li class="pft-directory">Penotypic<ul><input id="Penotypic" type="radio" name="uploads/Penotypic/" value="uploads/Penotypic/namPheno.csv" />namPheno.csv<br><input id="Penotypic" type="radio" name="uploads/Penotypic/" value="uploads/Penotypic/perl.pl" />perl.pl<br></ul></li></ul>
Jquery script:
$('#Penotypic').click(function() {
var $out1 = $('#trait');
$('#trait').show();
$out1.append('Submitted...');
});
this is not showing anything in the div trait. may be the html response is loading as a tesxt so the #Penotypic is not recognised. please help me to fix this.
Thanku
You have many inputs of id="Penotypic". Make every id unique or use classes as function trigger.
I wouldn't use "/" in the name attribute. See: http://www.w3.org/TR/html401/types.html#type-name
Then try if your ajax script does work. If it doesn't work, try if it works from static page (don't use your first jQuery script, but it's output as a static form). You probably need to bind your event trigger. Use jQuery's on().

Grails remoteLink ajax issue populating JQuery accordion

Following the simple example from Jquery: Accordion Example
Using a remoteLink function from grails (AJAX) the information is pulled back from the controller and sent back to the GSP, which works fine. I do however want this data to be placed within a Accordion container... click here for screenshot of current functionality.
(Event Create Page rendering form template) _form - GSP:
<g:remoteLink controller="event" action="showContacts" method="GET" update="divContactList">Show Contacts!</g:remoteLink>
<div id="divContactList">
<g:render template="contactListAjax" model="[contactList: contactList]" />
</div>
<script type="text/javascript">
$(document).ready(function()
{
alert("Checking if I'm ready :)");
$( "#accordion" ).accordion({
header: 'h3',
collapsible: true
});
});
</script>
_contactListAjax - GSP Template
<div id="accordion">
<g:each in="${contactList}" status = "i" var="contact">
<h3>${contact.contactForename}</h3>
<div><p>${contact.email}</p></div>
</g:each>
</div>
Not quite sure what I'm doing wrong here, as I'm encasing the data with the div with an id accordion, yet doesn't load. Please refer to screenshot link above to see what is currently happening.
UPDATE
Event (Standard Generated CRUD, only showing where the relivant imports are) create - GSP
<link rel="stylesheet" href="${resource(dir: 'css', file: 'jquery.ui.accordion.css')}"/>
<g:javascript src="jquery-1.7.1.min.js"></g:javascript>
<g:javascript src="jquery-ui.min.js"></g:javascript>
Try replacing:
$(function() {
$( "#accordion" ).accordion({
collapsible: true
});
})
with
$( "#accordion" ).accordion({
collapsible: true
});
Edit:
You can't use an <r:script /> tag after the request is finished. The server has already laid out all of the resources. Change it to a standard javascript tag. Also the inclusion of your javascript and css files should be elsewhere on the page.
I solved this... (well Hack & Slash for now... not the best, but only viable solution for now)
var whatever is the stored HTML generated by the AJAX and placed into the divContactList on the update function. The Accordion is deleted and then rebuilt (not the best approach I realise)
var whatever = $('#divContactList').html();
$('#accordion').append(whatever)
.accordion('destroy').accordion({
collapsible: true,
active: false
});

How to clear jquery validate errors

I'm hijaxing an existing form and POSTing to the server. jQuery validate does most of the validation but if validation fails on the server we return the errors to the client as JSON.
Below is the code that does that:
<script type="text/javascript">
$(function () {
$("form").submit(function (e) {
var $form = $(this);
var validator = $form.data("validator");
if (!validator || !$form.valid())
return;
e.preventDefault();
$.ajax({
url: "#Url.Action("index")",
type: "POST",
data: $form.serialize(),
statusCode: {
400: function(xhr, status, err) {
var errors = $.parseJSON(err);
validator.showErrors(errors);
}
},
success: function() {
// clear errors
// validator.resetForm();
// just reload the page for now
location.reload(true);
}
});
});
});
</script>
The problem is I can't seem to clear the validation errors if the POST is successful. I've tried calling validator.resetForm() but this makes no difference, the error messages added by the showError() call, are still displayed.
Note I'm also using the jQuery.validate.unobtrusive plugin.
You posted this a while ago, I don't know if you managed to solve it? I had the same problem with jQuery validate and the jQuery.validate.unobtrusive plugin.
After examining the source code and some debugging, I came to the conclusion that the problem comes from the way the unobtrusive plugin handles error messages. It removes the errorClass that the jQuery.validate plugin sets, and so when the form is reset, jQuery validate cannot find the error labels to remove.
I did not want to modify the code of the plugins, so I was able to overcome this in the following way:
// get the form inside we are working - change selector to your form as needed
var $form = $("form");
// get validator object
var $validator = $form.validate();
// get errors that were created using jQuery.validate.unobtrusive
var $errors = $form.find(".field-validation-error span");
// trick unobtrusive to think the elements were succesfully validated
// this removes the validation messages
$errors.each(function(){ $validator.settings.success($(this)); })
// clear errors from validation
$validator.resetForm();
note: I use the $ prefix for variables to denote variables that contain jQuery objects.
$("#form").find('.field-validation-error span').html('')
In .NET Core I have the form inside a builtin Bootstrap modal.
For now I'm manually removing the error message spans from their containers, once the modal is starting to show, by using the additional .text-danger class of the error message container like so:
$('#my-form').find('.text-danger').empty();
so that I don't rely on container .field-validation-error that might have been already toggled to .field-validation-valid.
The min.js versions of the libraries jquery.validate and jquery.validate.unobtrusive are loaded via the partial view _ValidateScriptsPartial.cshtml, so I played with them to see what resetForm() / valid() and native html form reset() do.
So in my case $('#my-form').data("validator").resetForm() only resets some validator internals, not the form and it doesn't trigger the onReset() function in the unobtrusive library. The $('#my-form').valid() indeed removes the errors in the modal, but only if the modal is fully shown and valid. The native html form reset() is the only one that triggers both onReset() of unobtrusive library, and then the resetForm() of the validator. So it seems like we need to trigger the native html form document.querySelector('#my-form').reset() to activate the reset functions of both libraries/plugins.
The interesting thing is that the unobtrusive library runs the simple jQuery empty() on the .field-validation-error class (the container of the error span message) only in its onSuccess() function, and not onReset(). This is probably why valid() is able to remove error messages. The unobtrusive onReset() looks like it's responsible only for toggling .field-validation-error class to .field-validation-valid. Hense we are left with a <span id="___-error">The error message</span> inside the container <span class="text-danger field-validation-error">...</span>.
May be I am wrong to clear the errors like this:
function clearError(form) {
$(form + ' .validation-summary-errors').each(function () {
$(this).html("<ul><li style='display:none'></li></ul>");
})
$(form + ' .validation-summary-errors').addClass('validation-summary-valid');
$(form + ' .validation-summary-errors').removeClass('validation-summary-errors');
$(form).removeData("validator");
$(form).removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse($(form));
};
I tried answer given in the comment by AaronLS but not got the solution so I just do it like this.
Maybe helpful to someone.
Here's the code I ended up using to clear/reset all errors. It's possible there's some redundancy in there, but it's working for me.
function removeValidationErrors(frmId) {
var myform = $('#' + frmId);
myform.get(0).reset();
var myValidator = myform.validate();
$(myform).removeData('validator');
$(myform).removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse(myform);
myValidator.resetForm();
$('#' + frmId + ' input, select').removeClass('input-validation-error');
}
The reason this is still an issue (even 6 years on) is that jQuery Validation doesn't have an event handler for when your form is valid; only for when it's invalid.
Unobtrusive Validation taps into the Invalid handler to add your errors to your Validation Summary elements. (Specifically, any element with data-valmsg-summary=true.) But because there's no Valid handler, there's no way for Unobtrusive Validation to know when they can be cleared.
However, jQuery Validation does allow you to supply your own showErrors method, which is called after every validation check, whether the result is valid or invalid. Thus, you can write a custom function that will clear those validation summary boxes if your form is valid.
Here's a sample that will apply it globally. (You could apply it to specific instances of your validators by using settings, but since I always want this functionality, I just put it in the defaults object.)
$.validator.defaults.showErrors = function () {
if (!this.errorList.length) {
var container = $(this.currentForm).find("[data-valmsg-summary=true]");
container.find("ul").empty();
container.addClass("validation-summary-valid").removeClass("validation-summary-errors");
}
// Call jQuery Validation's default showErrors method.
this.defaultShowErrors();
};
This also has the benefit of clearing the validation summary box the moment your form is valid, instead of having to wait for the user to request a form submission.
I couldn't find this documented anywhere, but you should be able to reset the form by triggering a specific event, reset.unobtrusiveValidation, to which unobtrusive listens.
Example here:
.validation-summary-valid, .field-validation-valid { display: none; }
.field-validation-error { display: block; color: #dc3545 }
.input-validation-error { border: 1px solid #dc3545 }
.validation-summary-errors { background-color: #dc3545; color: #fff; margin-bottom: .5rem; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/4.0.0/jquery.validate.unobtrusive.js"></script>
<form id="testForm">
<div class="validation-summary-valid" data-valmsg-summary="true">
Validation Summary:
<ul><li style="display:none"></li></ul>
</div>
<div>
<label for="first_name">first name:</label>
<input data-val="true" data-val-required="the 'first name' field is required" name="first_name" id="first_name" />
<span class="field-validation-valid" data-valmsg-for="first_name" data-valmsg-replace="true"></span>
</div>
<div>
<label for="last_name">last name:</label>
<input data-val="true" data-val-required="the 'last name' field is required" name="last_name" id="last_name" />
<span class="field-validation-valid" data-valmsg-for="last_name" data-valmsg-replace="true"></span>
</div>
<button type="submit">Submit form (click first)</button>
<button type="button" onclick="$('#testForm').trigger('reset.unobtrusiveValidation')">Reset form (click second)</button>
</form>

asp.net mvc partialview #Ajax.ActionLink doesn't work

I have a view page
my view page
<div id="beReplaced">
#Ajax.ActionLink("please click on me to bring the partial view",
"PatrialViewToBeCalled",
new AjaxOptions()
{UpdateTargetId = "beReplaced",
InsertionMode = InsertionMode.InsertAfter,
HttpMethod="Get",
LoadingElementId = "prgress" })
</div>
i have a Controller
public PartialViewResult PatrialViewToBeCalled()
{
var customer = db.Customers.First();
return PartialView("PartialViewThatMustBeShow",customer);
}
but when i click on the generated link it brings me to a new page instead of
replacing or appending the partial view to the div tag.
What's the problem?
It could have been that you were missing the:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
In the main view. This tells the main view to recognize the ajax helper.
I found the solution. The problem was due to the corrupted unobtrusive-ajax.min.js file.
If you have jQuery loaded into your page, why not use the simple jquery get / load method to get the partial view ?
<div id="beReplaced">
please click on me to bring the partial view
</div>
Javascript
$("#lnk1").click(function(){
$.get('/controller/PatrialViewToBeCalled', function(data) {
$('#beReplaced').html(data);
});
});
If you are working with ASP .NET MVC 4 make sure that
#Scripts.Render("~/bundles/jquery")
is in the end of the body tag as well.
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", required: false)
</body>
</html>
I've just been working on it for too long, thinking it did not work. Viewing the page source didn't show anything either.
Eventually, I found out it actually did work when I saw the successful requests in the console of Firebug. It only was showing it off screen. In the HTML tab of Firebug I finally found the output, even though it does not show up in the page source.

Running a function in a jQuery implicit context

My html document looks like this:
<html>
<head> .. load jquery and other stuff </head>
<body>
<div id="cool_container">
<div class="cool">.. no script friendly markup ..</div>
</div>
<a id="cool_link">Link</a>
<script>
function installStuff(){
$('.cool').coolPlugin();
$('#cool_link').click(function(){
$('#cool_container').load('/anothercooldiv.html');
});
}
$(document).load(function(){ installStuff(); });
</script>
</body>
</html>
Of course, /anothercooldiv.html gives another <div class="cool"> .. etc ...</div> fragment.
So what's the best way to turn the fresh cool div into a coolPlugin without breaking everything (and writing some nasty hacks) ?
It'd would be great to be able to either:
Call installStuff with a default jQuery context '#cool_container', so I could call something like:
$.doThisInContext(function(){installStuff();}, $('#cool_container');
In the load callback.
Or, have an equivalent of 'live' (that would solve the problem of links if cool contains links), but on an element existence, that I could use like that in my function installStuff:
$('.cool').exists(function(what){ what.coolPlugin() };
Then the coolPlugin would be installed on all cool elements now and in the future.
I'd suggest the .livequery() plugin for this still:
$(function() {
$('.cool').livequery(function() {
$(this).coolPlugin();
});
$('#cool_link').click(function(){
$('#cool_container').load('/anothercooldiv.html');
});
});
The important bit:
$('.cool').livequery(function() {
$(this).coolPlugin();
});
Will run for every current and future .cool element as they're added, running the plugin on each.
Applying the plugin to the newly ajax loaded content shouldn't be too tricky:
$('#cool_container').load('/anothercooldiv.html', function() {
$(this).coolPlugin();
});

Resources