Pass selector into javascript function - javascript

i have a js function that insert some code into exsiting html.
HTML
<div id="filteredProducts">
<!--load by js-->
</div>
<div id="filteredplaces">
<!--load by js-->
</div>
<div class="container">
<div class="bucket">
</div>
</div>
js code
var myfun = function (data) {
if (data.form_is_valid) {
$("#filtered1").html(data.html);
toggleLight();
}
I need further abstract it to take another paramter so that i can insert data.html into any selector. So "#filtered1" will become a parameter pass into this function.
For example (Not sure if it works)
var myfun = function (data, sel) {
if (data.form_is_valid) {
$(sel).html(data.html);
toggleLight();
}
Ideally i'd like to do following:
myfun(data,".container .bucket")
or
myfun(data,"#filteredplaces")

const myFunction = (data, selector) => {
if (data.isFormValid) {
$(selector).html(data.html);
// toggleLight();
}
};
myFunction({ isFormValid: true, html: '<h1>Hello</h1>'}, '.class1,.class2')
This seems to work as you intended. I just tested with the last line, and it does what you need.
Perhaps, you missed that you need a comma in between the classes when you are targeting multiple

Related

Getting info from HTML set in a variable in Javascript

I have something like this:
function (foo) {
}
Foo contains some HTML. For example:
<div>
<div>
<div class="myclass>
<div>
Hello World
</div>
</div>
</div>
</div>
I need to extract that info off the variable somehow.
I have tried:
function (foo) {
$('.myclass > script').text()
}
I probably need some way to select foo instead. Any help?
If you want to do this in jQuery then you need to convert the string of HTML held in foo in to a jQuery object which you can interrogate with jQuery methods to retrieve the data you need. For example:
function getText(foo) {
return $(foo).find('.myclass').text();
}
let input = '<div><div><div class="myclass"><div> Hello World</div></div></div></div>';
console.log(getText(input));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

How to pass variable to child function from HTML page

I want to pass a value from HTML page to child function from parent function.
HTML Page:
<div class="bottom_wrapper clearfix">
<div class="message_input_wrapper">
<input class="message_input" placeholder="Type your message here..." />
</div>
<div class="send_message">
<div class="icon"></div>
<div class="text">Send/div>
</div>
</div>
Parent Function Call:
$('.send_message').click(function (e) {
return [sendMessage(getMessageText()),sendMessage1(getMessageText1())];
});
$('.message_input').keyup(function (e) {
if (e.which === 13) {
return [sendMessage(getMessageText()),sendMessage1(getMessageText1())];
}
});
here getMessageText1 is child function.
Child Function:
getMessageText1 = function () {
var result="";
var id = Parent_FUNC_INPUT;
$.ajax({
url:"func.php",
type: 'POST',
data: ({id:id}),
async: false,
success:function(data) {
result = data;
}
});
I want to populate [[id]] variable in child function from parent function.
First, I'll do my best to clean up the HTML:
<div class="bottom_wrapper clearfix">
<div class="message_input_wrapper">
<input class="message_input" placeholder="Type your message here..." />
</div>
<div class="send_message">
<div class="icon"></div>
</div>
<div class="text">Send</div>
</div>
Using proper indentation will make things far easier to read. And while we're on the subject, you may want to use dashes - instead of underscores _ in your class names, as that's the common convention.
On to your question, it seems like what you want to do is simply pass an argument to getMessageText1 from within (as you refer to it) a "parent" function bound to an event listener.
So you'd define this "child" function with a single parameter:
function getMessageText1(Parent_FUNC_INPUT) {
...
var id = Parent_FUNC_INPUT;
...
}
And then you can just call it with getMessageText1(value) where value is whatever you want to pass in.
One more note: for readability's sake I recommend you do not name your functions the way you have. Having two functions getMessageText and getMessageText1 will just be a source of confusion later on. Instead, think of something more descriptive, ala getMessageTextFromID.
Hopefully I answered the question you meant to ask. Let me know.

ASP.NET MVC Core - JavaScript event handlers with dynamically loaded PartialViews [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
I have this script in my view file, the purpose of it is to populate a section of the same view, but only a small section of it, which is a HTML div with Bootstrap panel classes:
<script type="text/javascript">
function GetVehicles() {
$.get('#Context.Request.Scheme://#hostname/#controller/GetVehicles', {id: #Model.Id}, function (response) {
$("#tabOutVehicles").html(response);
});
}
function GetMedInfo() {
$.get('#Context.Request.Scheme://#hostname/#controller/GetMedInfo', {id: #Model.Id}, function (response) {
$("#tabOutMedInfo").html(response);
});
}
</script>
My complete view, which will display the output generated by the script above:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="~/js/site.js"></script>
<div class="panel panel-primary">
<div class="panel-heading">
Vehicles
</div>
<div id="collapseVehicles" class="panel-collapse collapse">
<div id="tabOutVehicles">
</div>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<strong style="color:white">Medical Info</strong>
</div>
<div id="collapseMedInfo" class="panel-collapse collapse">
<div id="tabOutMedInfo">
</div>
</div>
</div>
<script type="text/javascript">
function GetVehicles() {
$.get('#Context.Request.Scheme://#hostname/#controller/GetVehicles', {id: #Model.Id}, function (response) {
$("#tabOutVehicles").html(response);
});
}
function GetMedInfo() {
$.get('#Context.Request.Scheme://#hostname/#controller/GetMedInfo', {id: #Model.Id}, function (response) {
$("#tabOutMedInfo").html(response);
});
}
</script>
By clicking on the hyperlinks inside the Bootstrap panel divs, the jQuery method hits my controller action, returns the response, and then puts the response in the applicable div (#tabOutMedInfo / #tabOutVehicles). Both these actions return partial views. Here is what my partial view looks like, both look the same except for the model properties that differ:
#model MyViewModel
<div class="panel-body">
<a data-url="#Url.Action("EditMedInfo", "Controller", new { id = Model.Id })" data-toggle="ajax-modal" data-target="#EditMedInfo" class="btn btn-default">Edit</a>
<div class="form-horizontal">
<div class="">
<div class="form-group">
<div class="col-md-5 col-sm-5 col-xs-5"><label asp-for="Variable" class="control-label"></label></div>
<div class="col-md-7 col-sm-7 col-xs-7">
#Html.DisplayFor(item => item.Variable)
</div>
</div>
</div>
</div>
</div>
When the above hyperlink is clicked, it is supposed to execute JavaScript code that loads a modal for editing, which is not happening, instead it does not open the modal. The JavaScript code is located in my site.js file, which is being imported in my main view.
What I've tried:
I moved the script import tag to both my partial views and then removed it from my view, it then causes the JavaScript code to run and display my modal, but this solution only worked for a while.
New problem:
Then a new problem started occurring, if the first partial view is loaded, and you were to load the second partial view without closing the web page, it causes site.js to be loaded twice into the view, once by the first partial view, and a second time by the second partial view. With site.js loaded twice, it somehow causes my post action to be hit twice, resulting in data being inserted twice for one post action.
I then decided to move site.js to my _Layout.cshtml (ideally how it should be) and tried again, this way around caused the partial views to render like normal, but once again, the modals didn't show when clicking on the hyperlinks found in the partial views.
My theory:
The way I understand it, when the jQuery get methods loads the partial views, it prevents the partial view from seeing site.js, even though it was loaded in by my _Layout.cshtml.
What I preferrably don't want to change:
I don't want to get rid of my small get actions, I built it like this to keep my users as much as possible on one page, and calling the get actions seperately reduces their data usage.
Am I loading site.js correctly? Why doesn't my partial views see site.js?
Edit:
This is my _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
<environment names="Development">
#*Other scripts omitted *#
<script src="~/js/site.js" asp-append-version="true" defer></script>
</environment>
<environment names="Staging,Production">
#*Other scripts omitted *#
<script src="~/js/site.js" asp-append-version="true" defer></script>
</environment>
</head>
<body>
<div id="modal-placeholder"></div>
#RenderBody()
#RenderSection("scripts", required: false)
</body>
</html>
And here is the JavaScript code located inside site.js:
$(function () {
var placeholderElement = $('#modal-placeholder');
var redirectUrl = "";
$('a[data-toggle="ajax-modal"]').click(function (event) {
var url = $(this).data('url');
redirectUrl = window.location.href;
$.get(url).done(function (data) {
placeholderElement.html(data);
placeholderElement.find('.modal').modal('show');
});
});
placeholderElement.on('click', '[data-save="modal"]', function (event) {
event.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
var newBody = $('.modal-body', data);
placeholderElement.find('.modal-body').replaceWith(newBody);
var isValid = newBody.find('[name="IsValid"]').val() == 'True';
if (isValid) {
placeholderElement.find('.modal').modal('hide');
window.location.assign(redirectUrl);
}
}
});
});
});
The JavaScript was written like above to handle server side validation on modals, see the brilliant article here: https://softdevpractice.com/blog/asp-net-core-mvc-ajax-modals/
When you 'paste' the HTML for the panel into the page once returned from the ajax call, it breaks all existing event handlers. So you need to re-bind the handler anchor elements. I would wrap your event handler inside a function, and call that function both on initial page load and also in the ajax success handler (after you've pasted the HTML). Assuming you're using jQuery, it would look something like this:
function bindAjaxModalButtons() {
$('[data-toggle="ajax-modal"]').click(function() {
// ... your event handler code here
});
}
$(function() {
bindAjaxModalButtons(); // attaches event handlers on initial page load
});
Then change your ajax functions like so:
function GetMedInfo() {
$.get('#Context.Request.Scheme://#hostname/#controller/GetMedInfo', {id: #Model.Id}, function (response) {
$("#tabOutMedInfo").html(response);
bindAjaxModalButtons(); // <-- this will attach the event handler to the new buttons
});
}
EDIT: now that I can see your JS file, here is what it should look like:
$(function () {
var placeholderElement = $('#modal-placeholder');
var redirectUrl = "";
bindAjaxModalButtons();
placeholderElement.on('click', '[data-save="modal"]', function (event) {
event.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
var newBody = $('.modal-body', data);
placeholderElement.find('.modal-body').replaceWith(newBody);
var isValid = newBody.find('[name="IsValid"]').val() == 'True';
if (isValid) {
placeholderElement.find('.modal').modal('hide');
window.location.assign(redirectUrl);
}
}
});
});
});
function bindAjaxModalButtons() {
var btns = $('a[data-toggle="ajax-modal"]');
btns.unbind(); // <-- so that existing buttons don't get double-bound
btns.click(function (event) {
var url = $(this).data('url');
redirectUrl = window.location.href;
var placeholderElement = $('#modal-placeholder');
$.get(url).done(function (data) {
placeholderElement.html(data);
placeholderElement.find('.modal').modal('show');
});
});
}

How to call function dynamically in JQuery

I've set of html codes, I want to have a function for each set where I can pull some data or do some activities, so basically I need to be calling function according to the html codes present in DOM, suppose I've header section I want to collect menu items and I've sliders where I want to collect slider information, So I need to call header function to do the activity accordingly and slider function to do the activity, I went across some info about eval() but I guess it has lot of demerits and is being obsolete. Please suggest me how can I achieve it.
HTML Code:
Header
<div class="header" data-nitsid="1">
<div class="branding">
<h1 class="logo">
<img src="images/logo#2x.png" alt="" width="25" height="26">NitsOnline
</h1>
</div>
<nav id="nav">
<ul class="header-top-nav">
<li class="has-children">
Home
</li>
</ul>
</nav>
</div>
Slider
<div id="slideshow" data-nitsid="2">
<div class="revolution-slider">
<ul> <!-- SLIDE -->
<!-- Slide1 -->
<li data-transition="zoomin" data-slotamount="7" data-masterspeed="1500">
<!-- MAIN IMAGE -->
<img src="http://placehold.it/1920x1200" alt="">
</li>
</ul>
</div>
</div>
Now I want to collect data from both elements and pass the data to my views of laravel framework where it will generate a popup for each section for editing purpose.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design.nits();
}
var design = {};
design.1 = function() {
// do ajax request to views of header
}
design.2 = function() {
// do ajax request to views of slider
}
You canot use literal number as a property name. If you want to call property 1 of object design use design[1] instead. Also, you cannot assing property to non-initialized variable, you must use var design = {}; to make it object. If your property of design object is stored in nits variable, then call it as design[nits]();. Also, next time don't forget to test your code before posting it here. You've forget ) after your first function.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design[nits]();
});
var design = {};
design[1] = function() {
// do ajax request to views of header
};
design[2] = function() {
// do ajax request to views of slider
};
You want to use design[nits]();.
This will get the property nits of design and execute it with ().
But there is another problem. Your design will be declared after the each loop, so it is not available inside. You have to place it before.
$(function() {
var design = {};
design.funcOne = function() {
alert("funcOne called");
}
design.funcTwo = function() {
alert("funcTwo called");
}
$('div[data-nitsid]').each(function() {
var nits = $(this).data("nitsid");
design[nits]();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-nitsid="funcOne">
I will call 'funcOne'!
</div>
<div data-nitsid="funcTwo">
I will call 'funcTwo'!
</div>

Async loading a template in a Knockout component

I'm pretty experienced with Knockout but this is my first time using components so I'm really hoping I'm missing something obvious! I'll try and simplify my use case a little to explain my issue.
I have a HTML and JS file called Index. Index.html has the data-bind for the component and Index.js has the ko.components.register call.
Index.html
<div data-bind="component: { name: CurrentComponent }"></div>
Index.js
var vm = require("SectionViewModel");
var CurrentComponent = ko.observable("section");
ko.components.register("section", {
viewModel: vm.SectionViewModel,
template: "<h3>Loading...</h3>"
});
ko.applyBindings();
I then have another HTML and JS file - Section.html and SectionViewModel.js. As you can see above, SectionViewModel is what I specify as the view model for the component.
Section.html
<div>
<span data-bind="text: Section().Name"></span>
</div>
SectionViewModel.js
var SectionViewModel = (function() {
function SectionViewModel() {
this.Section = ko.observable();
$.get("http://apiurl").done(function (data) {
this.Section(new SectionModel(data.Model)); // my data used by the view model
ko.components.get("dashboard", function() {
component.template[0] = data.View; // my html from the api
});
});
}
return SectionViewModel;
});
exports.SectionViewModel = SectionViewModel;
As part of the constructor in SectionViewModel, I make a call to my API to get all the data needed to populate my view model. This API call also returns the HTML I need to use in my template (which is basically being read from Section.html).
Obviously this constructor isn't called until I've called applyBindings, so when I get into the success handler for my API call, the template on my component is already set to my default text.
What I need to know is, is it possible for me to update this template? I've tried the following in my success handler as shown above:
ko.components.get("section", function(component) {
component.template[0] = dataFromApi.Html;
});
This does indeed replace my default text with the html returned from my API (as seen in debug tools), but this update isn't reflected in the browser.
So, basically after all that, all I'm really asking is, is there a way to update the content of your components template after binding?
I know an option to solve the above you might think of is to require the template, but I've really simplified the above and in it's full implementation, I'm not able to do this, hence why the HTML is returned by the API.
Any help greatly appreciated! I do have a working solution currently, but I really don't like the way I've had to structure the JS code to get it working so a solution to the above would be the ideal.
Thanks.
You can use a template binding inside your componente.
The normal use of the template bindign is like this:
<div data-bind="template: { name: tmplName, data: tmplData }"></div>
You can make both tmplData and tmplName observables, so you can update the bound data, and change the template. The tmplName is the id of an element whose content will be used as template. If you use this syntax you need an element with the required id, so, in your succes handler you can use something like jQuery to create a new element with the appropriate id, and then update the tmplname, so that the template content gets updated.
*THIS WILL NOT WORK:
Another option is to use the template binding in a different way:
<div data-bind="template: { nodes: tmplNodes, data: tmplData }"></div>
In this case you can supply directly the nodes to the template. I.e. make a tmplNodes observable, which is initialized with your <h3>Loading...</h3> element. And then change it to hold the nodes received from the server.
because nodesdoesn't support observables:
nodes — directly pass an array of DOM nodes to use as a template. This should be a non-observable array and note that the elements will be removed from their current parent if they have one. This option is ignored if you have also passed a nonempty value for name.
So you need to use the first option: create a new element, add it to the document DOM with a known id, and use that id as the template name. DEMO:
// Simulate service that return HTML
var dynTemplNumber = 0;
var getHtml = function() {
var deferred = $.Deferred();
var html =
'<div class="c"> \
<h3>Dynamic template ' + dynTemplNumber++ + '</h3> \
Name: <span data-bind="text: name"/> \
</div>';
setTimeout(deferred.resolve, 2000, html);
return deferred.promise();
};
var Vm = function() {
self = this;
self.tmplIdx = 0;
self.tmplName = ko.observable('tmplA');
self.tmplData = ko.observable({ name: 'Helmut', surname: 'Kaufmann'});
self.tmplNames = ko.observableArray(['tmplA','tmplB']);
self.loading = ko.observable(false);
self.createNewTemplate = function() {
// simulate AJAX call to service
self.loading(true);
getHtml().then(function(html) {
var tmplName = 'tmpl' + tmplIdx++;
var $new = $('<div>');
$new.attr('id',tmplName);
$new.html(html);
$('#tmplContainer').append($new);
self.tmplNames.push(tmplName);
self.loading(false);
self.tmplName(tmplName);
});
};
return self;
};
ko.applyBindings(Vm(), byName);
div.container { border: solid 1px black; margin: 20px 0;}
div {padding: 5px; }
.a { background-color: #FEE;}
.b { background-color: #EFE;}
.c { background-color: #EEF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="byName" class="container">
Select template by name:
<select data-bind="{options: tmplNames, value: tmplName}"></select>
<input type="button" value="Add template"
data-bind="click: createNewTemplate"/>
<span data-bind="visible: loading">Loading new template...</span>
<div data-bind="template: {name: tmplName, data: tmplData}"></div>
</div>
<div id="tmplContainer" style="display:none">
<div id="tmplA">
<div class="a">
<h3>Template A</h3>
<span data-bind="text: name"></span> <span data-bind="text: surname"></span>
</div>
</div>
<div id="tmplB">
<div class="b">
<h3>Template B</h3>
Name: <span data-bind="text: name"/>
</div>
</div>
</div>
component.template[0] = $(data)[0]
I know this is old, but I found it trying to do the same, and the approcah helped me come up with this in my case, the template seems to be an element, not just raw html

Categories