Super newbie at Javascript here. I have a problem with whitespace that I'm hoping someone can help me with.
I have a function that looks like this:
function createLinks()
{
var i = 0;
tbody = document.getElementsByTagName('tbody')[3];
console.log('test order ID: '+document.getElementsByTagName('tbody')[3].getElementsByTagName('tr')[0].getElementsByTagName('td')[1].textContent.replace(/^\s+|\s+$/g,''))
trs = tbody.getElementsByTagName('tr');
console.log('trs.length = '+trs.length);
for (i=0;i<trs.length;i++)
{
orderId = trs[i].getElementsByTagName('td')[1].textContent.replace(/^\s+|\s+$/g,'');
console.log('order: '+orderId);
hrefReturn = 'https://www.example.com/example.html?view=search&range=all&orderId='+orderId+'+&x=13&y=17';
linkReturn = '<a href='+hrefReturn+'>'+orderId+'</a>';
console.log(linkReturn);
trs[i].getElementsByTagName('td')[1].innerHTML = linkReturn;
}
}
I call this function using another function when the page is initially loaded. This works perfectly.
However, I also call this function in another way when data on the page changes. There's a dropdown list that I have an onClick attribute attached to. That onClick event calls the first function, which in turn calls the second function (above). Both of these functions are saved into text variables and appended to the document, as below:
var scriptTextLinks = " function createLinksText() { var i = 0; tbody = document.getElementsByTagName('tbody')[3]; console.log('test order ID: '+document.getElementsByTagName('tbody')[3].getElementsByTagName('tr')[0].getElementsByTagName('td')[1].textContent.replace(/^\s+|\s+$/g,'')); trs = tbody.getElementsByTagName('tr'); console.log('trs.length = '+trs.length); for (i=0;i<trs.length;i++) { orderId = trs[i].getElementsByTagName('td')[1].textContent.replace(/^\s+|\s+$/g,'').replace(/\s/g,''); orderId = orderId.replace(/\s/g,''); console.log('order: '+orderId); hrefReturn = 'https://www.example.com/example.html?view=search&range=all&orderId='+orderId+'+&x=13&y=17'; linkReturn = '<a href='+hrefReturn+'>'+orderId+'</a>'; console.log(linkReturn); trs[i].getElementsByTagName('td')[1].innerHTML = linkReturn; } console.log('complete'); } "
Finally, here is the specific problem. When THIS version of the same function is called by events on the webpage, it fails to properly delete the whitespace, which breaks the link that it's supposed to create.
This is the exact problem section of code:
orderId = trs[i].getElementsByTagName('td')[1].textContent.replace(/^\s+|\s+$/g,'').replace(/\s/g,''); orderId = orderId.replace(/\s/g,''); console.log('order: '+orderId);
So instead of storing the variable like it should, like this:
"XXXXXXXXX"
It is stored like this:
"
XXXXXXXXXX
"
Which, again, kills the link.
Can anybody clarify what's going on here, and how I can fix it? Thanks in advance!
To strip all that surrounding whitespace you can use the standard .trim() method.
var myString = " \n XXXXXXX \n ";
myString = myString.trim();
You can strip all leading and trailing, and compress internal whitespace to a single space, as is normally done in HTML rendering, like this...
var myString = " \n XXXX \n YYYY \n ";
myString = myString.replace(/\s+/g, " ").trim();
Also, see tharrison's comment below.
(though my /\s+/g pattern worked fine with the embedded \n newlines)
Cure for IE<9
"shim.js"
(function() {
if (! String.prototype.trim) {
//alert("No 'trim()' method. Adding it.");
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/mg, '');
};
}
})();
(Or, if you might want to do other things in your shim...)
var shim = {
init: function() {
if (! String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/mg, '');
};
}
}
};
shim.init();
Your HTML file
<script type="text/javascript" src="shim.js"></script>
Related
I'm having some trouble trying to get multiple checkbox values. It currently is working, just not in the way I wanted/was hoping it would. Right now anything checked is appended to the bottom of the body and not inline with the function it was aiming to be inserted into.
I'm trying to avoid using JQuery or anything except JavaScript as it's all we've currently covered in our class.
function favMedia(media){
var media = document.forms['mediapref']['media'].value;
return media;
}
function pets(pet){
var pet = document.getElementsByName('pets')
for (var checkbox of pet){
if (checkbox.checked)
document.body.append(checkbox.value + ' ');
}
}
function about(text){
var info = document.forms['personal']['about'].value;
return info;
}
function infoForm(media, pet, text){
document.getElementById('infoset').innerHTML = favMedia(media) + "<br>" + pets(pet) + "<br>" + about(text);
}
Is there some way I can assign it just to a single variable to return and then throw into the last function?
Also please give me any tips or improvements on any aspect of the functions if you have any.
Put it in a string that you return from the function.
function pets(pet) {
var pet = document.querySelector('[name="pets":checked');
let selected = [...pet].map(p => p.value);
return selected.join(', ');
}
I am creating a demo-website for a fictional company.
The most of it is written in Javascript but I have a problem that all my functions are getting called on every HTML-page, even if they are not getting used.
Example: I have a Contact page where only one function should be called, but right now all functions are being called. Those for my Booking page and so on.
I am trying to use window.addEventListener together with window.location.pathname without result.
function start() {
// variable for pathname. split in to substrings by '/'
var pathArray = window.location.pathname.split('/');
// check the last substring of the array for determening which script to
run
if(pathArray[pathArray.length-1] == "contact.html")
{
browserDetect();
}
else if(pathArray[pathArray.length-1] == "ourfleet.html")
{
showFirstFleetImg();
showFleetImg();
}
else if(pathArray[pathArray.length-1] == "employees.html")
{
showFirstStaffImg();
showStaffImg();
}
}
window.addEventListener("load", start, false);
One of the functions
function showFleetImg(arrayno) {
var fleethtml = "";
var caption = document.getElementById("planename");
for(var i = 0; i < fleetarray.length; i++) {
fleethtml = fleethtml + "<a href = '#' onclick = 'showFleetImg(" + i +
"); return false; '><img src='" + fleetarray[i] + "' /></a>";
}
fleetimage.src = fleetarray[arrayno];
caption.innerHTML = planename[arrayno];
document.getElementById("fleetthumbs").innerHTML= fleethtml;
}
function showFirstFleetImg(imgnum) {
showFleetImg(0);
}
window.addEventListener("load", showFirstFleetImg, false);
What more do I add, or how do I structure this right so function X is only called in HTML file Y?
It looks like you are looking for something like ES Modules. There is a lot of information here http://exploringjs.com/es6/ch_modules.html, but the gist is they encapsulation javascript code so that functions aren't executed right away.
If you rewrite your javascript file to something like
// foo.js
export function showFleetImg(arrayno) {
var fleethtml = "";
var caption = document.getElementById("planename");
for(var i = 0; i < fleetarray.length; i++) {
fleethtml = fleethtml + "<a href = '#' onclick = 'showFleetImg(" + i +
"); return false; '><img src='" + fleetarray[i] + "' /></a>";
}
fleetimage.src = fleetarray[arrayno];
caption.innerHTML = planename[arrayno];
document.getElementById("fleetthumbs").innerHTML= fleethtml;
}
export function showFirstFleetImg(imgnum) {
showFleetImg(0);
}
and then your other js file will look like
import {showFleetImg, showFirstFleetImg} from './foo.js'
function start() {
// variable for pathname. split in to substrings by '/'
var pathArray = window.location.pathname.split('/');
// check the last substring of the array for determening which script to
run
if(pathArray[pathArray.length-1] == "contact.html")
{
browserDetect();
}
else if(pathArray[pathArray.length-1] == "ourfleet.html")
{
showFirstFleetImg();
showFleetImg();
}
else if(pathArray[pathArray.length-1] == "employees.html")
{
showFirstStaffImg();
showStaffImg();
}
}
There is nothing in the code you've posted to suggest each function should first every time.
However, there are many better ways to do what you're trying to do.
Use separate JS files and call into each page only those that need to be executed
If you prefer to use one JS file like currently, don't conditionalise based on pathname; what if your filename changes? You'd have to update your JS each time.
As regards the latter point, it would make more sense to act on the presence (or lack thereof) of a data attribute on the body identifying which page is currently showing.
HTML
<body data-page='contact'>
JS
switch (document.body.getAttribute('data-page')) {
case 'contact': /* do something */ break;
case 'fleet': /* do something else */ break;
//etc...
}
Note also the use of switch() rather than duplicative if/else if statements.
[Edit - or have a look at Modules as per #user1816294's answer]
This chunk of code that I have updates the color of the text but not the actual text...
var lastWordTyped;
var ele = document.querySelector("#my_text");
//code
//...
lastWordTyped = capitalizeFirstLetterOfKeyword(lastWordTyped);
lastWordTyped = lastWordTyped.fontcolor("blue");
ele.innerHTML = lastWordTyped;
function capitalizeFirstLetterOfKeyword(keyword) {
var word;
word = keyword.charAt(0).toUpperCase() + keyword.slice(1);
return word;
}
When I step through it, is recognizing what the new string should be but it doesnt update the actual text to the new string, but it does change its color. Can anybody provide me with the reason as to why it won't update it?
You haven't declared lastWordTyped, so the capitalizeFirstLetterOfKeyword() gets an 'undefined' as input.
Working demo here:
http://jsfiddle.net/yc4mvm1n/1/
var lastWordTyped = "NewWord";
var ele = document.querySelector("#my_text");
lastWordTyped = capitalizeFirstLetterOfKeyword(lastWordTyped);
lastWordTyped = lastWordTyped.fontcolor("blue");
ele.innerHTML = lastWordTyped;
function capitalizeFirstLetterOfKeyword(keyword) {
var word;
word = keyword.charAt(0).toUpperCase() + keyword.slice(1);
return word;
}
Your code looks fine to me.
http://plnkr.co/edit/mRllGWD2bNTxxyWrJENZ?p=preview
Try posting some more code.
function capitalizeFirstLetterOfKeyword(keyword) {
var word;
word = keyword.charAt(0).toUpperCase() + keyword.slice(1);
return word;
}
is returning proper capitalized word back, I am assuming that you are setting values to lastWordTyped somewhere in your //code section
Make sure the element #my_text exists before the JS code is run. You can do this by putting the script at the bottom of the body, or by using
window.onload = function() {
// your code here
}
Good day.
My question is quite dumb, I guess, but I'm not familiar enough with the termins, to ask it properly (and to get an answer from Google).
So - please help...
Shortly - I'm trying to create some major class, which will be insanitated by instances, which will describe some methods, and some fields.
Major logick will be implemented in parent class.
So, lets say I have a parent
function CRUD_Grid_model(){
//Settings part
this.GridElement = "" ;
this.editModeFlagElement = "" ;
this.newRowElement = "";
//Save logicks all lies here.
this.commit = function (){
alert("PLEASE REDEFINE COMMIT FUNCTION IN YOUR CODE");
}
;
//Settings part
//Some more code.
}
And a way I'll use it
//Das modell
var JobberCRUD = new CRUD_Grid_model();
JobberCRUD.GridElement = $('#jobbers_dg');
JobberCRUD.editModeFlagElement = $('#jobbers_tb_edit');
JobberCRUD.newRowElement = {jobb_name:'Enter new unique name',jobb_status:'Y'};
JobberCRUD.commit = function (){
if (this.endEditing()){
var addrows = this.GridElement.datagrid('getChanges','inserted');
var remrows = this.GridElement.datagrid('getChanges','deleted');
var updrows = this.GridElement.datagrid('getChanges','updated');
console.log(addrows);
console.log(remrows);
console.log(updrows);
//Send changes?
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
//Commit changes at local level
this.GridElement.datagrid('acceptChanges');
}
};
And, what I'd like to do, is smoething like this
I want a parent.commit function to allow me to do this in child
JobberCRUD.commit = function (apdrows,updrows,remrows){
//Send changes?
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
};
So, I have no ideas what shoudl I do to achieve that. Please advice me with some tags, what it is at least :)
Thanks in advance.
There is not exactly what you need in JavaScript, but I would tend to use this pattern :
function CRUD_Grid_model() {
...
this.onCommit = null;
this.commit = function (){
if (this.endEditing()){
var addrows = this.GridElement.datagrid('getChanges','inserted');
var remrows = this.GridElement.datagrid('getChanges','deleted');
var updrows = this.GridElement.datagrid('getChanges','updated');
if(this.onCommit != null) this.onCommit(addrows,updrows,remrows);
this.GridElement.datagrid('acceptChanges');
}
}
...
}
var JobberCRUD = new CRUD_Grid_model();
JobberCRUD.onCommit = function(apdrows,updrows,remrows) {
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
};
JobberCRUD.GridElement = ...
Javascript doesn't have a built in notion of interfaces. A javascript object effectively "implements an interface" by having all the needed methods defined, but there's no language "interface" construct
You could use "extends" like so:
Object.prototype.extends = function(clazz) {
var o = new clazz();
for (var f in o) {
if(f === "extends") {
continue;
}
this[f] = o[f];
}
this.super = o;
}
Now could type something like this:
var JobberCRUD = function() {
this.extends(CRUD_Grid_model);
var privateFunction = function() {
//...
}
// You probably don't want to do that,
// but you could override
this.commit = function() {
//...
}
// ...
}
Hope, that helps.
Edit: forgot, that you may call super.commit() then.
You can not have something similar like C# or Java interface or even class with Javascript.
Javascript is just a dynamic scripting language.
I am trying to integrate meteor with another JS framework. I had things working fairly well prior to the latest Blaze upgrade (i.e. pre-version 0.8). In order to get this to work, I need to render a meteor template as an HTML string. Moreover, I need to be able to supply a data object to provide the values for the variables included in the template.
Pre 0.8, I could simply do the following:
var myTemplateName = 'someTemplateName';
var myTemplateVariableData = {myTemplateVariableData: {'xxx': 'some data}};
var myTemplateHTML = Template[myTemplateName].render(myTemplateVariableData);
Of course, that no longer works. However, I have to think there is some way to do this still even post-0.8. I have gotten fairly close with the following:
var myTemplateVariableData = {'xxx': 'some data};
var templateName = 'someTemplateName';
var myTemplateHTML = "";
var dr = new UI.DomRange; // domain range
var loadedTemplate = Template[templateName].extend(
{
data: function () {
return { myTemplateVariableData: myTemplateVariableData }
}
}
);
var renderedTemplate = loadedTemplate.render();
UI.materialize(renderedTemplate, dr, null, dr.component);
for (var member in dr.members) {
if (dr.members.hasOwnProperty(member)) {
var testHTML = dr.members[member].innerHTML;
if (testHTML) {
myTemplateHTML = myTemplateHTML + testHTML
} else {
myTemplateHTML = myTemplateHTML + dr.members[member].textContent
}
}
}
The problem with the result of this attempt is that if I try something like this:
{{#if myTemplateVariableData.xxx}}<span> {{myTemplateVariableData.xxx}}</span>{{/if}}
I will get the span showing up but no content other than the  . It seems as though when inside of an if block, it loses the context and can't see the myTemplateVariableData attribute on the 'this' object any longer.
I suspect there is an easier way to accomplish what I am trying to do here but I am out of ideas at present so I thought I'd post this here to see if anyone else had tried to do something similar.
My solution I think is a little more straight forward:
function html(contextObject, templateName) {
return Blaze.toHTML(Blaze.With(contextObject, function() { return Template[templateName]; }));
}
use:
template file
<template name="myTemplate">
<div id="{{myid}}"></div>
</template>
in some JS file
var myhtml = html({myid : 11}, "myTemplate") //<div id="1"></div>
To answer your question in the title, you could do it like this:
var templateName = 'myTemplate'
var context = {randomNumber: 527}
var div = document.createElement('div')
var component = UI.renderWithData(Template[templateName], context)
UI.insert(component, div)
var htmlString = div.innerHTML // <-- What you want.
But that's maybe not what you want?