Wrap all non-child HTML into a DOM-element - javascript

I am working on a little hyphenation engine for a website, and I got to get my head around this. I am matching all p.hyphenatable and send the content to a PHP-script to have it hyphenated like this:
jQuery(".hyphenatable").each(function() {
var hyphenatableObject = jQuery(this);
if (hyphenatableObject.children().size() == 0){ // Hyphenate only if there is no child elements to prevent HTML from being omitted
jQuery.ajax({
type: "POST",
url: phpHyphenatorUrl,
data : {
language:hyphenationLang,
text: hyphenatableObject.text()
},
dataType: "html",
success: function(data) {
hyphenatableObject.html(data);
}
});
}
});
To be able to have this script work on elements with children as well, I would like to wrap the non-encapsulated parts of the matched selectore into new elements, and send those to the web service. For example:
<p>My text <img src="img.jpg" /> with image</p>
becomes
<p><span class="whatever">My text</span> <img src="img.jpg" /> <span class="whatever">with image</span></p>
Any ideas on that?

Related

Add class/text to a jQuery element

I'm trying to clone the following HTML template and add class/text to it.
<template id="result">
<section>
<div class="alert">
<p class="someText"></p>
</div>
</section>
</template>
So the user first submits a question:
<div id="answer"></div>
<section class="row">
<form id="form" action="/" method="GET">
<div>
<input id="question" />
</div>
</form>
</section>
Then the script executes:
$(document).ready(function () {
$('#form').on('submit', function (event) {
$.ajax({
data: {...},
type: 'GET',
url: '/result'
}).done(myFunction);
});
});
And finally it clones the template (ID #result), add a class to the element containing a class alert and add some text to the element containing a class someText, and appends it to the element containing ID #answer.
function myFunction(result) {
clone = $('#result').clone();
$('.alert', clone).addClass('myClass');
$('.someText', clone).text('myText');
clone.appendTo("#answer");
}
The function executes (I added a console.log() to the end of it to be sure) but nothing is appending.
Consider the following.
function create_message(result) {
var section = $("#result").children().clone();
$('.alert', section).addClass(result.status);
$('.address', section).text(result.address);
$('.extract', section).text(result.extract);
$('.question', section).text(result.question);
section.appendTo("#answer");
}
This creates a clone of all the HTML Elements inside the Template with ID result. It then finds specific classes inside the Object section and makes changes.
You can also do the following.
section.find(".alert").addClass(result.status);
See more: https://api.jquery.com/clone/
Update
Use <template> to hold some content that will be hidden...
So if you Clone the Template and append it, it will still be hidden.
Try the following:
function myFunction(result) {
clone = $('#result > section').clone();
$('.alert', clone).addClass('myClass');
$('.someText', clone).text('myText');
clone.appendTo("#answer");
}
Update 2
I don't use <template>, so I had to re-read some stuff. It has a content portion, so it has an HTML Fragment contained within and is not like other HTML Elements, more like an iFrame. So we need to collect the content versus cloning it.
See: How to use HTML template tag with jQuery?
Here is a working example: https://jsfiddle.net/Twisty/rpd9h0mf/20/
Your code will be something more like the following.
JavaScript
$(function() {
function showResults(results) {
var clone = $($('#result').html());
$('.alert', clone).addClass(results.class);
$('.someText', clone).text(results.answer);
clone.appendTo("#answer");
}
$('#question-form').submit(function(event) {
event.preventDefault();
$.ajax({
data: {
q: $("#question").val()
},
type: 'GET',
url: '/result',
success: showResults
});
});
});
This creates a new jQuery Object based on the HTML Content of the Template. Now you can properly edit it and append it.

How to modify values of a template html inside a variable

I have an Ajax call that gets different description, and url address of a video:
function TraerInstructivos() {
$.ajax({
type: "GET",
url: '<%= Page.ResolveUrl("~/Instructivo/Instructivos.aspx") %>' + '/TraerInstructivos',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var res = JSON.parse(response.d);
$.each(res, function (i, item) {
DibujarVideo(item);
});
},
error: function (response) {
alert("Error");
}
});
};
Now DibujarVideo is the method that will grab the template I have in my ascx, make a copy and then append it. This is the HTML of the ascx:
<div id="Videos">
</div>
<template id="video-elem">
<div class="row">
<div class="col-lg-4">
<font id="video-desc" size="3"></font>
<br />
<br />
<p><a id="video-ref" class="btn btn-secondary" href="#" role="button">Mira el Video ยป</a></p>
</div>
</div>
<br />
<hr />
</template>
Right now, the method that copies the template html looks like this:
function DibujarVideo(video) {
var elemACrear = $("#video-elem").html();
$(elemACrear).find("#video-ref").attr("href", video.DireccionVideo);
console.log(elemACrear);
$("#Videos").append(elemACrear);
}
What I see in the console log, and the page is that the value of href is not changing, but If I save this in a variable I see the changes for example:
var elem = $(elemACrear).find("#video-ref").attr("href", video.DireccionVideo);
So I reckon is not the same changing/manipulating the DOM tree in a page vs in a variable.
How can I change that href inside my elemACrear variable?
Im learning jQuery, every help appreciated.
You've already diagnosed and solved the issue without following the logic through. You simply need to provide the jQuery object you create in the elem variable to the append() call, like this:
function DibujarVideo(video) {
var elemACrear = $("#video-elem").html();
var $elem = $(elemACrear);
$elem.find("#video-ref").attr("href", video.DireccionVideo);
$("#Videos").append($elem);
}

How do I replace variables in HTML with an object of variables from jQuery?

I am trying to make a system for my web page that gets the content of a template found in the HTML and then replaces the appropriate variables with the corresponding values which is stored in an object. The problem is that nothing is being replaced. In this example, I am getting the contents of an RSS file that displays forum posts. I use ajax to get the contents, then iterate through each item. I assign the xml tag values to an object whose keys correspond to the variabls in the HTML template. For every post found, it should replace the HTML variable with the contents of the xml tag.
This is my Javascript:
$.ajax({
url: "rsstest.xml",
type: "GET",
dataType: 'xml',
crossDomain: true,
success: function(xml){
var news = $('#news-results');
news.empty();
if($(xml).find('item').length > 0){
$(xml).find('item').each(function(){
var temp_vars = {
news_title: $(this).find('title').text(),
news_body: $(this).find('description').text(),
news_date: $(this).find('pubDate').text(),
news_link: $(this).find('link').text()
}
var template = $('#news-template').contents().clone();
for(const variable in temp_vars){
template.text().replace("{"+variable+"}", temp_vars[variable])
}
news.append(template);
})
} else {
news.append($('<p></p>').text('There is no news to display at this time.'));
}
}
})
This is my HTML:
<h1>Announcements</h1>
<div id="news-results">
</div>
<div id="news-template" style="display: none;">
<div class="media">
<div class="media-body">
<h3>{news_title}</h3>
<p>{news_body}</p>
<div class="media-footer">
<div class="col-left">
<h4>Posted on {news_date}</h4>
</div>
<div class="col-right">
Read More
</div>
</div>
</div>
</div>
</div>
What am I doing wrong?
Code below will only replace the text without assigning it.
template.html().replace("{"+variable+"}", temp_vars[variable])
You have to assign after replacing the text to update the actual value.
template.html(template.html().replace("{"+variable+"}", temp_vars[variable]))

Unable to remove css class and add a new one

I have this function that goes through each breadcrumb in a navbar and I want to change the styling of the breadcrumb depending what page they are on.
Here is the basic HTML of the breadcrumb navbar
<div id="WCBar">
<div class="bc_nav current span" id="bc_main">
<a class="bc_1" id="lnkCrumb" href="javascript:__doPostBack('ctl00$breadcrumbnav1$ctl00$lnkCrumb','')">
<li>Account Info</li></a>
<span class="step-arrow"></span>
<input name="ctl00$breadcrumbnav1$ctl00$hdnPageName" id="hdnPageName" type="hidden" value="WCQuoteMain2.aspx">
</div>
<div class="bc_nav a" id="bc_main">
<a class="aspNetDisabled bc_2" id="lnkCrumb"> <li>Rate</li></a>
<span class="step-arrow"></span>
<input name="ctl00$breadcrumbnav1$ctl01$hdnPageName" id="hdnPageName" type="hidden" value="WCQuoteRatingV4.aspx">
</div>
<div class="bc_nav a" id="bc_main">
<a class="aspNetDisabled bc_3" id="lnkCrumb"><li>Questions</li></a>
<span class="step-arrow"></span>
<input name="ctl00$breadcrumbnav1$ctl02$hdnPageName" id="hdnPageName" type="hidden" value="questions.aspx"></div>
<div class="bc_nav last" id="bc_main">
<a class="aspNetDisabled bc_4" id="lnkCrumb"><li>Final</li></a>
<span class="step-arrow" style="background-image: none;"></span>
<input name="ctl00$breadcrumbnav1$ctl03$hdnPageName" id="hdnPageName" type="hidden" value="managesubmission.aspx"></div>
I then call this function in Javascript:
function WCBar(pagename, iframepagename, currentSet) {
$('.bc_nav', $('#WCBar')).each(function () {
iframepagename = $(this).find('input[id*="hdnPageName"]').attr('value');
var bcMain = $(this).find('div[id*="bc_main"]');
var lnkCrumb = $(this).find('a[id*="lnkCrumb"]');
if (pagename == iframepagename) {
//bcMain.addClass("current span");
bcMain.attr("class", "current span");
currentSet = 1;
// notify server
$.ajax({
type: "POST",
url: window.location.pathname + "/UpdateIFrameBreadcrumb",
data: "{'pagename':'" + iframepagename + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
// alert(msg.d);
},
error: function (msg) {
// alert(msg.d);
}
});
}
else {
if (lnkCrumb[0].href.length > 1) { //&& currentSet == 0
//bcMain.attr("class", "bc_nav enabled span");
bcMain.removeClass("bc_nav");
bcMain.addClass("bc_nav enabled span");
}
else {
//bcMain.attr("class", "bc_nav a");
bcMain.removeClass();
bcMain.addClass("bc_nav a");
}
}
});
}
When I mouse over bc_Main during a debugging session, context > className shows the proper class but trying to determine if bc_main has a class results in
?bcMain.hasClass('bc_nav');
false
in Visual Studio's Immediate window.
Furthermore, trying to determine what the values are in class gets me an undefined error.
var x = bcMain.attr('class');
undefined
No class is ever removed from bc_main, no matter if I try .removeClass() and leave it empty or try .removeClass('bc_nav');
I have checked to make sure nothing is defaulting elsewhere and can't find anything.
Thanks for your help.
It looks like a scope issue. You are using THIS to perform your find which shouldn't find itself. Your .bc_nav elis actually your #bc_main el, so you might as well just treat $(this) as bcMain. I don't know why you are iterating on both .bc_nav and #WCBar, seems like you should only use .bc_nav.
$('.bc_nav', $('#WCBar')).each(function () {
...
var bcMain = $(this).find('div[id*="bc_main"]');
saying $(this) in this instance is the same as saying $('.bc_nav') so you are essentially doing $('.bc_nav').find('div[id*="bc_main"]'); which won't work since #bc_main isnt' a child of .bc_nav.
If you are trying to empty the class attribute use:
$('#myElementID').removeAttr('class');
or this
$('#myElementID').attr('class', '');
To remove a specific class, you have to use the class name:
$('#myElementID').removeClass('myClassName');
Also, FWIW, in the else statement, this line
bcMain.removeClass("bc_nav");
is pointless, being that it's followed by this one
bcMain.addClass("bc_nav enabled span");

jQuery - on load of element with ajax

I searched for some time but could not find a working solution for my problem (sorry if I searched wrongly)...
I would like to have the equivalent of the following function for an element loaded with ajax:
$(document).ready(function() {
$('.div-modal-text').css("background-color","red");
});
Therefore I am using the following code:
$('#parent_id').on('action', '#id or class to be born', function to be performed() );
In my example the parent-child structure is: #projectModals (div whose content is dynamically loaded)>...>.div-project-description>.div-modal-text
This translates into the following code in my example:
$('#projectModals').on('load', '.div-project-description', function() {
$(this).find('.div-modal-text').each(function() {
$(this).css("background-color","red");
});
});
I know 'load' does not work with .on(), but I tried different alternatives and I could not find anything working.
Thanks for your help!
EDIT: Here is my (simplified) HTML code:
<div id="projectModals"></div>
content loaded in #projectModals with Ajax:
<div class="row">
<div class="div-project-idcard">
column 1, don't bother too much about this column
</div>
<div class="div-project-description">
<div id="summary" class="div-modal-text">
Column2, text 1
</div>
<div id="purpose" class="div-modal-text"">
Column2, text 2
</div>
<div id="reforestation" class="div-modal-text">
Column2, text 3
</div>
<div id="certification" class="div-modal-text">
Column2, text 4
</div>
</div>
</div>
If you're waiting for it to be loaded via ajax, consider using $(window).ajaxSuccess() instead:
$(window).ajaxSuccess(function(){
$('#projectModals .div-project-description .div-modal-text').each(function() {
$(this).css("background-color","red");
});
});
for what I understand, you want to change some background color after an ajax has been executed.
I think it's best to make the operation in the ajax success
$.ajax({
url: "some url",
data: {some data},
success: onAjaxSuccess,
});
and then;
function onAjaxSuccess(data){
//.. do things with data
var toExecute = $('#projectModals .div-project-description');
toExecute.find('.div-modal-text').each(function() {
$(this).css("background-color","red");
});
}

Categories

Resources