CSHTML button with javascript onlick function only works some times? - javascript

I have a download button set up on a web page that is iteratively assigned an ID based on the how many questions are posted.
Here is the button:
<input data-bind="attr: { id: $index() }" type="button" value="Download" class="download" />
Here is the the JS function that finds the number assigned and does the onclick:
#Scripts.Render("~/bundles/knockout")
<script type="text/javascript">
var SDNo = 0;
$(document).ready(function () {
SystemJS.import('sd/questions').then(function (modules) {
//Code here for another section that fills out the questions not relevant apart from assigning SDNo
});
SystemJS.import('sd/download').then(function (modules2) {
var attachVM = new modules2.Attachment();
//$("#download").click(function () {
$("input[class^='download'], input[class*=' download']").each(function () {
$(this).click(function () {
var id = $(this).attr('id');
let passedValue = id.concat("-" + SDNo);
attachVM.download(passedValue);
});
});
});
The above function allows me to go off to a typescript file and handle the required API call to GET a file
that code is here:
typescript
export class Attachment {
async download(ID: Number) {
window.open(await WebApi.getJSON('SD', 'Download', Number));
}
}
So yeah it'll work then it'll randomly stop working for no reason that I can find and obviously no errors thrown, via debugging it doesn't even get into the typescript file at all nothing happens. But then sometimes it goes all the way through into the controller doing what it needs to do.

As per #LouysPatriceBessette
$("input[class^='download'], input[class*=' download']").each(function () {
$(this).click(function () {
var id = $(this).attr('id');
let passedValue = id.concat("-" + SDNo);
attachVM.download(passedValue);
});
to
$("input.download").on("click", function() {
var id = $(this).attr('id');
let passedValue = id.concat("-" + SDNo);
attachVM.download(passedValue);
});
And it works consistently now thank you again.

Related

How do I assign a jQuery object to a variable?

So I have two autocomplete containers. Instead of writing code twice, I will use the same autocomplete call.
But in order to triger correct autocomplete (read: populate correct result list), I need to assign it to a variable. I've done this a long time ago, but I have forgotten how I did it.
So I have the following:
autocomplete: function () {
var autocompleteInput = null;
var autocompleteResultList = null;
$('.autocomplete').on("input", function (e) { // I have 2 of these
autocompleteInput = $(this); // This is the input i'm working with
autocompleteResultList = autocompleteInput.closest('.autocomplete-result');
resourcesData(autocompleteInput.val());
}).on('focus', function (e) {
autocompleteInput.val(''); //Cannot read property 'val' of null
}).on('blur', function (e) {
autocompleteResultList.removeClass('is-active');
});
}
My HTML x 2 (short version)
<div class="autocomplete-wrapper">
<input class="autocomplete" type="text" >
<input class="resource-id" type="hidden">
<div class="autocomplete-result"></div>
</div>
I'm pretty sure it' some basic jQuery knowledge in regards of setting a variable = a jQuery object (autocompleteInput = $(this);) and how it all works that I've forgotten.
Any help appreciated :)
PS. I'm not using jQuery autocomplete - I've made my own.
You have to abandon the variables that you share across the different event callbacks. But since they are easy to derive, just do that in each event handler itself.
Some things to note:
The closest method only looks to parents, not to siblings, so use the siblings method instead (or if your structure is slightly different than in your question, maybe .closest(".autocomplete-wrapper").find(".autocomplete-result")).
resourcesData is currently not provided with any information about where it should populate the data, so you should pass it an extra argument for it to know where to populate, and deal with that argument in that function.
Suggested code would then be:
autocomplete: function () {
$('.autocomplete').on("input", function (e) {
// extra argument
resourcesData($(this).val(), $(this).siblings('.autocomplete-result'));
}).on('focus', function (e) {
$(this).val('');
}).on('blur', function (e) {
$(this).siblings('.autocomplete-result').removeClass('is-active');
});
}
So after good help from Patric, Baao and Trincot (and others), I got it working. So just want to share my working solution just incase others are facing similar issues. It's probably not the most elegant solution, but it's working :)
let resources = {
init: function () {
this.searchResources();
},
searchResources: function () {
var self = this;
$('.autocomplete').on("input", function (e) {
let term = $(this).val();
if(term.length > 1){
self.autocomplete($(this));
}
}).on('focus', function (e) {
$(this).val('');
}).on('blur', function (e) {
$(this).closest('.autocomplete-result').removeClass('is-active');
});
},
autocomplete: function(obj){
let url = 'http://localhost.no:8080/resources%TERM';
url = url.replace('%TERM', '/' + $(obj).val() );
var resultList = $(obj).siblings('.autocomplete-result');
let source = $('#autocomplete-list').html();
let template = Handlebars.compile (source);
$.ajax({
method: "GET",
url: url,
dataType: "json",
success: function(result) {
let content = template({resources: result.data});
$(resultList).html(content);
$('.autocomplete-list-item').on('click', function (e) {
$(obj).siblings('input.resource-id').val($(this).data('resource-id'));
$(obj).val($(this).data('resource-name'));
$(resultList).removeClass('is-active');
console.log($(this).data('resource-id'));
console.log($(this).data('resource-name'));
});
},
error: function(err){console.log(err);}
}).done(function () {
var resultList = $(obj).siblings('.autocomplete-result');
if(!$(resultList).hasClass('is-active')){
$(resultList).addClass('is-active')
}
});
}
};
One of my input fields looks like this:
<div class="input-field column is-6 autocomplete-wrapper">
<input id="autocomplete-owner" class="autocomplete" autocomplete="off" type="text" >
<label for="autocomplete-owen">Prosjektleder</label>
<input id="resource-id-owner" class="resource-id" type="hidden" name="resource-id-owner">
<div class="autocomplete-result"></div>
</div>

executing javascript function on page load

Right now, I have a javascript function which is triggered onclick. However, I want the same function to be triggered when DOM is loaded. Following code works, however, I don't want to put 'script' tag in the middle of the view. Calling the function from the body tag is not an option here.
<script>document.addEventListener("DOMContentLoaded",function(){extractions.RefreshCheck(#check.ID)});</script>
Code snippet of where I want to implement this:
#foreach (var check in Model.FailedChecks)
{
<li class="#( check.IsOK ? Html.Raw("bg-success") : Html.Raw("bg-danger") ) " cid="#check.ID">
#Html.ActionLink(check.Display, "XList", "XList", new { filter = check.GetQuery(), Layout = check.Layout }, new { target = "_blank" });
<span class="glyphicon glyphicon-refresh" onclick="extractions.RefreshCheck(#check.ID);" onload="initAutoRefresh"></span>
#*<script>document.addEventListener("DOMContentLoaded",function(){extractions.RefreshCheck(#check.ID)});</script>*#
</li>
}
Above codes work, but I do not want that script tag in my view. So I tried to add the following code in my javascript file using 'onload' eventlistner and it does not work. I think this is the problem.
#foreach (var check in Model.FailedChecks)
{
<li class="#( check.IsOK ? Html.Raw("bg-success") : Html.Raw("bg-danger") ) " cid="#check.ID">
#Html.ActionLink(check.Display, "XList", "XList", new { filter = check.GetQuery(), Layout = check.Layout }, new { target = "_blank" });
<span class="glyphicon glyphicon-refresh" onclick="extractions.RefreshCheck(#check.ID);" onload="extractions.InitAutoRefresh()"></span>
</li>
}
And my InitAutoRefresh function :
var extractions= {
InitAutoRefresh: function () {
if (document.readyState === 'complete') {
RefreshCheck();
console.log("function already loaded in DOM")
} else {
document.addEventListener('DOMContentLoaded', function () {
RefreshCheck();
console.log("function loaded in dom");
});
}
},
RefreshCheck: function(intCheckId){
$('li[cid=' + intCheckId + ']').addClass('bold');
$.get(window.location + '/Home/UpdateIntegritycheck?checkId=' + intCheckId, function(data){
$('li[cid='+intCheckId+']').replaceWith(data);
});
}
}
Function RefreshCheck works fine on click (i.e. it updates record). I would be more than happy to get your feedbacks. Thank you.
One approach is to define custom attribute on your html tags on which you can fire conditionaly according to the tag value. Example :
<span data-click-on-dom-ready="true" onclick="extractions.RefreshCheck(#check.ID);" ></span>
Then far away from your partial view, you can put the following:
$(document).ready(function () {
$("[data-click-on-dom-ready='true']").trigger('click');
});
Try this code:
#section scripts{
<script>document.addEventListener("DOMContentLoaded", function () { xtractions.RefreshCheck(id) });</script>
}
if you are using jquery then you can use
$(document).ready(function () {
your code here
});

Jquery .change() event fires only once

So I'm fairly novice with jquery and js, so I apologise if this is a stupid error but after researching I can't figure it out.
So I have a list of data loaded initially in a template, one part of which is a dropdown box that lets you filter the data. My issue is that the filtering only works once? As in, the .change function inside $(document).ready() only fires the once.
There are two ways to reload the data, either click the logo and reload it all, or use the search bar. Doing either of these at any time also means the .change function never fires again. Not until you refresh the page.
var list_template, article_template, modal_template;
var current_article = list.heroes[0];
function showTemplate(template, data)
{
var html = template(data);
$("#content").html(html);
}
$(document).ready(function()
{
var source = $("#list-template").html();
list_template = Handlebars.compile(source);
source = $("#article-template").html();
article_template = Handlebars.compile(source);
source = $("#modal-template").html();
modal_template = Handlebars.compile(source);
showTemplate(list_template,list);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = list.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
$("#classFilter").change(function()
{
console.log("WOW!");
var classToFilter = this.value;
var filteredData =
{
heroes: list.heroes.filter(function(d)
{
if (d.heroClass.search(classToFilter) > -1)
{
return true;
}
return false;
})
};
console.log(filteredData);
showTemplate(list_template,filteredData);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = filteredData.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
});
$("#searchbox").keypress(function (e)
{
if(e.which == 13)
{
var rawSearchText = $('#searchbox').val();
var search_text = rawSearchText.toLowerCase();
var filteredData =
{
heroes: list.heroes.filter(function(d)
{
if (d.name.search(search_text) > -1)
{
return true;
}
return false;
})
};
console.log(filteredData);
showTemplate(list_template,filteredData);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = filteredData.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
}
});
$("#logo").click(function()
{
showTemplate(list_template,list);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = list.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
});
//$("#logo").click();
});
function displayModal(event)
{
var imageNumber = $(this).data("id");
console.log(imageNumber);
var html = modal_template(current_article.article[0].vicPose[imageNumber]);
$('#modal-container').html(html);
$("#imageModal").modal('show');
}
I should note two things: first, that the search bar works perfectly, and the anonymous function inside both of them is nearly identical, and like I said, the filtering works perfectly if you try it after the initial load. The second is that the same problem occurs replacing .change(anonymous function) with .on("change",anonymous function)
Any help or advice would be greatly appreciated. Thanks.
I agree with Fernando Urban's answer, but it doesn't actually explain what's going on.
You've created a handler attached to an HTML element (id="classFilter") which causes part of the HTML to be rewritten. I suspect that the handler overwrites the HTML which contains the element with the handler on it. So after this the user is clicking on a new HTML element, which looks like the old one but doesn't have a handler.
There are two ways round this. You could add code inside the handler which adds the handler to the new element which has just been created. In this case, that would mean making the handler a named function which refers to itself. Or (the easier way) you could do what Fernando did. If you do this, the event handler is attached to the body, but it only responds to clicks on the #classFilter element inside the body. In other words, when the user clicks anywhere on the body, jQuery checks whether the click happened on a body #classFilter element. This way, it doesn't matter whether the #classFilter existed when the handler was set. See "Direct and delegated events" in jQuery docs for .on method.
Try to use some reference like 'body' in the event listeners inside your DOM like:
$('body').on('click','.articleButton', function() {
//Do your stuff...
})
$('body').on('click','#classFilter', function() {
//Do your stuff...
})
$('body').on('keypress','#searchbox', function() {
//Do your stuff...
})
$('body').on('click','#logo', function() {
//Do your stuff...
})
This will work that you can fire it more than once.

Javascript not working when jquery is added

I am new to javascript n jquery. I used javascript along with jquery on my script tag.When jquery is not added, the javascript works fine,but when a jquery function is added, the script is not working.....shall i convert both to javascript or both to jquery or am i missing anything.Here is my script
<script type="text/javascript">
function getLocations() {
$.post('#Url.Action("getLocations","Home")', { 'id': $("#cities").val() },
function (data) {
$("#loca").html(data).show();
});
}
$(function () {
$('.submit').on('click', function () {
var ck = "";
var city = $("#cities option:selected").text();
var location = $("#loca option:selected").text();
alert(city+"and"+location)
}
});
</script>
here i am loading location based on the city selected.Its works fine when the onclick is not there,But when added ,location are not loading n the function is not calling.I have tried by butting alert inside it.Do i need do any thing else for both to work....Thank You
you forgot a )
$(function () {
$('.submit').on('click', function () {
...
}) // <---
});
if you properly indent the code blocks and if you look on the javascript console, this kind of errors become easier to be detected. Just adopt an indent style and write code adhering to it.

changing to Web Workers from AJAX setInterval

I have a script (below) that asynchronously updates markup on setInterval; markup which is generated with jQuery from XML data. This is my attempt at creating a UI in which users can view to see changes happen to the XML data in real-time. However, this is seeming like a round about way of acheiving the desired effect compared to Web Workers API; I am finding out that my AJAX script and setInterval function are unreliable; the script appears to freeze or not respond at certain initial loads and after running for long periods of time points . How can I modify my code to use workers instead of AJAX or setInterval?
setInterval(refreshXml, 1500);
function refreshXml() {
var req = $.get('Administration/data/people.xml');
req.done(function(xml) {
// Update the global XML variable used to create buttons.
window.peopleXml = xml;
// Clear existing buttons.
$('#loadMe').empty();
// Display a button for each XML person entity.
$(xml).find('fullName').each(function(index) {
var fullName = $(this).text();
$('<button>', {
'class': 'mybutton',
value: $(this).siblings('id').text(),
text: fullName
}).appendTo('#loadMe');
});
// Update any person divs that were already visible.
$('#toadMe .person').each(function() {
// Grabs the ID from data-person-id set earlier.
var id = $(this).data('person-id');
show_person(id);
});
});
}
function show_person(id) {
$('#person-detail-' + id).remove();
get_person(id).appendTo('#toadMe');
}
function get_person(id) {
var $person = $(window.peopleXml).find('id:contains(' + id + ')').parent();
var $div = $('<div>', {
'class': 'person',
'data-person-id': id,
id: 'person-detail-' + id
});
$('<h1>', { text: $person.find('firstName').text() }).appendTo($div);
$('<h1>', { text: $person.find('lastName').text() }).appendTo($div);
$('<h1>', { text: $person.find('age').text() }).appendTo($div);
$('<h1>', { text: $person.find('hometown').text() }).appendTo($div);
$('<h1>', { text: $person.find('job').text() }).appendTo($div);
return $div;
}
$(document).on('click', '.mybutton', function() {
$('#toadMe').empty();
show_person(this.value);
});
The name of the above script is home.js and here is an example of an index page (index.html) and a worker (my_task.js):
// index.html
<script>
var myWorker = new Worker("my_task.js");
myWorker.onmessage = function (oEvent) {
console.log("Worker said : " + oEvent.data);
};
myWorker.postMessage("ali");
// my_task.js
postMessage("I\'m working before postMessage(\'ali\').");
onmessage = function (oEvent) {
postMessage("Hi " + oEvent.data);
};
How can I implement home.js in a way in which index.html and my_task.js are implemented? Thanks a ton, I am really just looking for a way to get starting using workers as the next level up since I just recently learned AJAX. Also, I know this could possibly be seen as a broad question so I am willing to improve my question upon request and suggestions.

Categories

Resources