Merge value in string using jquery / javascript - javascript

I am making string contains values. I have company name, product and its value. I want to store these value in string but if user choose same product of same company then I want to only append product no only.
current string value TATA#434#tyre,TATA#234#door,TATA#687#tyre, and it should be as
TATA#434,687#tyre,TATA#234#door
as we can see user choose same company with same production, only product no. is different so we need to append only product no.
if customer choose all four product then string should be read like this
TATA#434,687#tyre,TATA#234#door,Maruti#8776#door
company and product can be increase. also in last entry how to remove ",".
Here is attached fiddle.
Code
var str="";
$('a').click(function(){
var el= $(this).parent();
str += el.find('#brand').text() + "#" + el.find('#no').text() + "#" + el.find('#product').text() +",";
console.log(str)
})

My real advice would be to use an object. Why? Because it makes your data manipulation SO much easier my friend.
Use something like:
function car(val1,val2,val3,val4) {
this.val1 = val1;
this.val2 = val2;
this.val3 = val3;
this.val4 = val4;
}
Now we can just make one with:
var item1 = new car("TATA#434","687#tyre","TATA#234#door","Maruti#8776#door");
Now you can change whatever you want.
If you would like further guidance on how to display this in the format you've suggested, more than happy to help.
Your solution involves many RegEx... which can turn sour quickly. As a large scale developer, I advice against this if there is any chance your values will change format in the future.
Using Arrays:
Here is a use case:
http://jsfiddle.net/k6XFy/1/
var a = ["TATA#434","687#tyre","TATA#234#door","Maruti#8776#door"];
function display(x){
alert(x);
}
alert(a[1]);
a[1] = "Convert";
alert(a[1]);
alert(a);
Edit:
You can join the array like so:
var a = ["TATA#434","687#tyre","TATA#234#door","Maruti#8776#door"];
function display(x){
alert(x);
}
var b = a.join(',');
alert(b);
View here: http://jsfiddle.net/k6XFy/3/

Why would you not store it in an object?
This is how I would store it.
{TATA: { 434: 'tyre', 234: 'door' }, Maruti: { 8776: 'door' }}
If you need to use it as a string, loop through it constructing the string when you need it.
EDIT:
I'm not sure the exact context, but perhaps this would even make sense:
{TATA: { tyre: [434,687], door: [234] }, Maruti: { door: [8776] }}
or
{ tyre: { TATA: [434,687] }, door: { Maruti: [8776], TATA: [234] }}

Related

How can I concatenate two strings into a variable name with Javascript or jQuery?

This question has been asked before, I wanted to create a (possibly) simpler version for others to (maybe) understand easier.
What I wanted to do was combine a string with the data (string) from a variable to create a variable name. I suppose it would be called a dynamic variable?
In this example I want to add a class and text to a div..
<div class="time fa"></div>
..based on changing data which I get from a json file.
var timetain = 10;
var timebus = 20;
var icontrain = 'fa-train';
var iconbus = 'fa-bus';
var type = 'bus'; // this string comes from a json file, it will either be train or bus
So I want to add the word time to the data from the variable named type to output the data from either timetrain or timebus
$('.time').text('Travel by bus will take |'time'|+|type| minutes');
$('.time').addClass(|'icon'|+|type|));
I suppose another way of wording the question would be "How to combine a variable's data with a string to get the data from a third variable with Javascript?"
Using ES6 template literals:
var time = "30",
typesArr = ["bus", "train", "foot"],
type = typesArr[ Math.random()*typesArr.length|0 ]; // pick random array item
// mix values with strings:
document.write( `Travel by ${type} will take ${time} minutes` );
Basically you cannot construct a variable name in javascript, unless it is an Object's Key, so you have to store the keys in some object in order to access them, but in your case it's much easier:
$('.time').addClass('icon fa-' + type); // example => 'icon fa-train'
But if you really wanted to construct the keys dynamically you could do:
var types = {
train : "fa-train",
bus : "fa-bus"
};
var whatever = "bus";
var type = types[whatever]; // "fa-bus"
Why not make an associative array of the times?
time = {'bus': 20, 'train': 10}
etc.? Than just access it with time[type]. This is much safer than what you want to do (you would have to rely on eval), which seems like overkill for this.
Nicht so #Hastig, lieber ordentlich machen.
A better solution without using Eval:
Most programming languages nowadays support a data-structure to "group" variables that belong together. It's called an Object. I can't come up with a single disadvantage in using Objects over multiple variables.
This approach is even (a teeny tiny bit) faster than your attempt with eval().
var configByType = {
"train": {
label: "train",
time: 10,
icon: "fa-train"
},
"bus": {
label: "bus",
time: 20,
icon: "fa-bus"
}
}
function travel(type){
//because creating and adding a new `span` is simpler
//than checking wich classes to remove on `.time.fa`
var $span = $('.time').html('<span>').children();
if(type in configByType){
let config = configByType[type];
$span.addClass(config.icon)
.text('Travel by '+ config.label +' will take ' + config.time + ' minutes')
}else{
$span.text('unsupported type: ' + type);
}
}
$('#update').click(function(){
var types = ["car", "bus", "train", "plane"];
var randomType = types[Math.floor(Math.random() * types.length)];
travel(randomType)
});
travel('bus');
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="time fa"></div>
<br>
<input id="update" type="button" value="update" />
A Solution Using Eval
eval('string' + variableName)
Applied To Provided Code
var timetain = 10;
var timebus = 20;
var icontrain = 'fa-train';
var iconbus = 'fa-bus';
var type = 'bus'; // this data (string) comes from a json file, it will either be train or bus
$('.time').text('Travel by bus will take ' + eval('time' + type) + ' minutes');
$('.time').addClass(eval('icon' + type));
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="time fa"></div>
Note
Before using this solution be sure to read more about the criticisms of using eval
This solution works and addresses the question as asked. I assume the downvotes are because of the criticisms that I pointed out and that there are better ways to go about things if properly planned but we'll never know because nobody cared to explain themselves.
I needed the simple eval way because I was putting together a complicated web of different json file comparisons for a simple game app and needed a quick and easy 'variable-variable', php-style method as placeholder code until I was able to better think everything through.
In the more advanced versions I am using objects and arrays like recommended in the other answers here but I was unable to think through things without using eval as temporary 'scaffolding'.
Fiddle
https://jsfiddle.net/Hastig/o169ja8w/

how do I loop through this database and get the child values?

I have this database, which looks like this
so the first keys are user uid taken from auth, and then the username he/she provided and what did they score for each match are taken also..
I just wanted to get each user total points - for example Ray total points is 45 and Wood total points is 44 but after looking through for the docs all I was able to do was just for one user, I have to write each user name and the specific match for each line to get the value.. now think of how it will be if they are dozens of users? hmm a lot of lines..
here is the JSON
the javascript code
var query = firebase.database().ref();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var Data1 = childSnapshot.child("Ray/Match1/Points").val();
var Data2 = childSnapshot.child("Ray/Match2/Points").val();
console.log(Data1 + Data2);
});
})
which will let me display, Ray total points, but not for Wood obviously I have to repeat it and write it..
So how do i solve this?
I took a look at your problem and I think I have your solution, or at the very least a PATHWAY to your solution. Ok, first I'll explain the basic issue, then I'll attempt to provide you with some generic-ish code (I'll attempt to use some of the variables you used). And away we go!
Basically what I see is 2 steps...
STEP 1 - You need to use a "constructor function" that will create new user objects with their own name (and/or user ID) and their own set of properties.
With that line of thinking, you can have the constructor function include properties such as "user name", "match points 1", "match points 2" and then a function that console logs the summary of each name and their total points from match points 1 and 2.
STEP 2 - You need to put the constructor function inside of a loop that will go through the database looking for the specific properties you need to fill in the properties needed by the constructor function to spit out the info you're looking for.
So... and let's take a deep breath because that was a lot of words... let's try to code that. I'll use generic properties in a way that I think will make it easy for you to insert your own property/variable names.
var user = function(name, match1, match2){
this.name = name;
this.match1 = match1;
this.match2 = match2;
this.pointTotal = function(match1, match2) {
console.log(match1 + match2);};
this.summary = function(){
console.log(name + " has a total of " + pointTotal + "
points.");};
}
the "This" part of the code allows ANY user name to be used and not just specific ones.
Ok, so the code above takes care of the constructor function part of the issue. Now it doesn't matter how many users you need to create with unique names.
The next step is to create some kind of loop function that will go through the database and fill in the properties needed to create each user so that you can get the total points from EVERY user and not just one.
Again, I will use generic-ish property/variable names...
var key = childSnapshot.key;
while(i = 0; i < key.length + 1; i++) {
var user = function(name, match1, match2){
this.name = name;
this.match1 = match1;
this.match2 = match2;
this.pointTotal = function(match1, match2) {
console.log(match1 + match2);};
this.summary = function(){
console.log(name + " has a total of " + pointTotal + " points.");};
}
}
That is a whole lot of words and the code is a hybrid of generic property names/variables and of property names/variables used by you, but I'm certain that I am on the correct pathway.
I have a lot of confidence that if you used the code and EXPLANATION that I provided, that if you plug in your own variables you will get the solution that you need.
In closing I just want to say that I REALLY hope that helps and if it doesn't I'd like to help solve the problem one way or another because I need the practice. I work a job with weird hours and so if I don't answer right away I am likely at my job :(
Good luck and I hope I helped!
simply add total node to your db
|_Id
|_ $userId:
| |_ Ray
| | |_ Match1:24
| | |_ Match2:21
| |_ total:45
and then get user`s total
var query = firebase.database().ref();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var total = childSnapshot.child("total").val();
console.log(total);
});
})
you can add the total node using cloud functions
Check out this implementation. No need for cloud function.
firebase().database().ref().on('value', function(snapshot) {
snapshot.forEach((user)=>{
user.forEach((matches)=> {
var total = 0;
matches.forEach((match)=> {
total += match.val().Points;
});
console.log(total);
});
});
})
If the key is the user's Id, why add yet another nested object with the user's name? Do you expect one user to have multiple usernames? That sounds weird and adds on complexity, as you have probably noticed. If you need to keep the user name somewhere in Firebase, it is recommended that you dedicate a user details section somewhere directly under the user Id key. Here is a JavaScript representation of the Firebase object structure:
{
a1230scfkls1240: {
userinfo: {
username: 'Joe'
},
matches: {
asflk12405: {
points: 123
},
isdf534853: {
points: 345
}
}
}
}
Now, getting to the total points seems a bit more straightforward, does it not? 😎
To help you without modifying your current database structure, all you need is to loop through all the userId+username+matches permutation in your database. Here is an example code to achieve just that, you do not need any special Firebase feature, just good old JavaScript for-of loop:
const query = firebase.database().ref();
query.once('value')
.then(snapshot => {
const points = {}
const users = snapshot.val()
for (const userId of Object.keys(users)) {
const userprofile = users[userId]
for (const username of Object.keys(userprofile)) {
const user = userprofile[username]
for (const matchId of Object.keys(user)) {
const match = user[matchId]
// Store the points per user, per profile, or per both, depending on your needs
points[username] = points[username] === undefined
? points[username] = match.points
: points[username] += match.points
}
}
}
})

setting object through variable containing strings not working

I have developed a pretty basic audio player on on my website similar to SoundClouds.
I have managed to successfully finish it, and I am starting to clean up all the markup, including (trying) removing all inline event handlers (i.e: onclick="" or onkeyup="").
However, I have come across a bit of a problem in my JavaScript whilst doing this.
It's a bit hard to explain so I'm going to post my JavaScript, then give you an idea of what the problem is:
$(".track-w__trigger").click(function(){
var tid = $(this).attr('aria-trackid'); // aria-trackid is equal to a random integer created by PHP
var tiW = 'w' + tid + 'w'; // this is an object (i.e: w3w)
playPauseButton(this, tiW, ti);
});
function playPauseButton(button, wave, trackID){
var button = $(button);
if(wave.isPlaying()){ // the object (w3w.isPlaying())
button.removeClass("playing");
wave.pause();
} else {
button.addClass("playing");
wave.play();
}
}
What I used to have was
<div class="track-w__trigger" onclick="playPauseButton(this, w3w, 3)" id="w3w-trigger"></div>
and now it is:
<div class="track-w__trigger" aria-trackid="3" id="w3w-trigger"></div>
As you can see in the second block of code. w3w is an object. However, because I have set it using my click function in a separate script using string quotes. JavaScript has gone ahead and made it a string.
So now when I use wave.isPlaying() for example; it does nothing.
I have no idea how to fix this, and no result on Google will help me. Any help in fixing this issue would be greatly appreciated,
Thanks!
EDIT:
This is where & how w3w is set:
var w3w = Uki.start({
// e.t.c
});
Use eval
wave = eval(wave);
to evaluate the string as a function
or use a safer way
wave = window[wave];
https://jsfiddle.net/zmr412q7/
Instead of having each object as a seperate variable, create an object that contains each object at the id representing the N in wNw. Ex:
var wNw = {};
// represents w1w
wNw[1] = (Uki.start({
// e.t.c
}));
// represents w17w
wNw[17] = (Uki.start({
// e.t.c
}));
// represents w3w
wNw[3] = (Uki.start({
// e.t.c
}));
This gives you an object that looks like:
{
1: object_that_was_w1w
17: object_that_was_w17w
3: object_that_was_w13w
}
And then your click handler looks like this:
$(".track-w__trigger").click(function(){
var tid = $(this).attr('aria-trackid'); // aria-trackid is equal to an integer of 1 to 5
var tidNum = parseInt(tid);
playPauseButton(this, wNw[tidNum], ti);
});
You can try something like this,
var tid='w'+5+'w';
var tryout=tid.valueOf();
console.log("getting the object "+tryout)
The valueOf property converts the string to an object

Using concatenation and a passed parameter to loop through an array

var Animals = {
"Europe": { "weasel.jpg": "squeak", "cow.jpg": "moo"},
"Africa": { "lion.jpg": "roar", "gazelle.jpg": "bark"},
};
function region(a){
var b = "Animals."+a;
for(var index in b) {
var target = document.getElementById('div1');
var newnode = document.createElement('img');
newnode.src = index;
target.appendChild(newnode)
}
}
RELEVANT HTML
<li onclick="europe('Europe')">Europe</li>
Goal: on the click of the Europe <li>, pass the word Europe into my region function where it is then concatenated to produce Animals.Europe
This is in order to identify an array within the object structure at the top using the for(var index in Animals.Europe) loop. Why is the concatenation which produces Animals.Europe not treated in the same way as if I had typed this out?
In addition, you can see that I have used arrays to store an image source and description for different animals. Using my limited coding knowledge this was all I could think of. Is there an easier way to store image/description data in order to produce in HTML?
"Animals." + a is just a string value, e.g. "Animals.Europe", which is not the same thing as Animals.Europe. If you change the first line to var b = Animals[a];, you should be all set.
Edit: and as elclanrs pointed out, it should be region('Europe'), not europe('Europe').
Why is the concatenation which produces Animals.Europe not treated in the same way as if i had typed this out?
In this case the variable b is just a string ("Animals.Europe"), which is treated like any other string (i.e. a list of characters). This means that when you attempt to loop through it (for(index in b)) you will be looping over a simple list of characters.
What you can do instead is use the square brace notation of accessing an objects properties. This means you can instead write var b = Animals[a], retrieving attribute a from Animals. You can read more about working with objects in this way on this MDN page
You can access the europe property using the following
Animals[a]
Also you're calling a "europe" function when you should be calling "region"
You're not storing animals in arrays here, but in objects with the image names as keys. Usually you'll want to use relevant names as keys. For example if you want arrays of animals for each continent
var Animals = {
"Europe": [{
imageSrc: "weasel.jpg",
cry: "squeak"
},{
imageSrc: "cow.jpg",
cry: "moo"
}],
"Africa": [{
imageSrc: "lion.jpg",
cry: "roar"
},{
imageSrc: "gazelle.jpg",
cry: "bark"
}]
};
Now Animals['Europe'] gives an array of objects, where you could eventually store other properties. So if b is an array your loop will now look like:
var b = Animals['Europe'];
for(var i=0; i < b.length; i++) {
var target = document.getElementById('div1');
var newnode = document.createElement('img');
var animalData = b[i]; // The array item is now an object
newnode.src = animalData.imageSrc;
target.appendChild(newnode)
}

Backbone.js - Filter a Collection based on an Array containing multiple keywords

I'm using Backbone.js/Underscore.js to render a HTML table which filters as you type into a textbox. In this case it's a basic telephone directory.
The content for the table comes from a Collection populated by a JSON file.
A basic example of the JSON file is below:
[{
"Name":"Sales and Services",
"Department":"Small Business",
"Extension":"45446",
},
{
"Name":"Technical Support",
"Department":"Small Business",
"Extension":"18800",
},
{
"Name":"Research and Development",
"Department":"Mid Market",
"Extension":"75752",
}]
I convert the text box value to lower case and then pass it's value along with the Collection to this function, I then assign the returned value to a new Collection and use that to re-render the page.
filterTable = function(collection, filterValue) {
var filteredCollection;
if (filterValue === "") {
return collection.toJSON();
}
return filteredCollection = collection.filter(function(data) {
return _.some(_.values(data.toJSON()), function(value) {
value = (!isNaN(value) ? value.toString() : value.toLowerCase());
return value.indexOf(filterValue) >= 0;
});
});
};
The trouble is that the function is literal. To find the "Sales and Services" department from my example I'd have to type exactly that, or maybe just "Sales" or "Services". I couldn't type "sal serv" and still find it which is what I want to be able to do.
I've already written some javascript that seems pretty reliable at dividing up the text into an array of Words (now updated to code in use).
toWords = function(text) {
text = text.toLowerCase();
text = text.replace(/[^A-Za-z_0-9#.]/g, ' ');
text = text.replace(/[\s]+/g, ' ').replace(/\s\s*$/, '');
text = text.split(new RegExp("\\s+"));
var newsplit = [];
for (var index in text) {
if (text[index]) {
newsplit.push(text[index]);
};
};
text = newsplit;
return text;
};
I want to loop through each word in the "split" array and check to see if each word exists in one of the key/values. As long as all words exist then it would pass the truth iterator and get added to the Collection and rendered in the table.
So in my example if I typed "sal serv" it would find that both of those strings exist within the Name of the first item and it would be returned.
However if I typed "sales business" this would not be returned as although both the values do appear in that item, the same two words do not exist in the Name section.
I'm just not sure how to write this in Backbone/Underscore, or even if this is the best way to do it. I looked at the documentation and wasn't sure what function would be easiest.
I hope this makes sense. I'm a little new to Javascript and I realise I've dived into the deep-end but learning is the fun part ;-)
I can provide more code or maybe a JSFiddle if needed.
Using underscore's any and all make this relatively easy. Here's the gist of it:
var toWords = function(text) {
//Do any fancy cleanup and split to words
//I'm just doing a simple split by spaces.
return text.toLowerCase().split(/\s+/);
};
var partialMatch = function(original, fragment) {
//get the words of each input string
var origWords = toWords(original + ""), //force to string
fragWords = toWords(fragment);
//if all words in the fragment match any of the original words,
//returns true, otherwise false
return _.all(fragWords, function(frag) {
return _.any(origWords, function(orig) {
return orig && orig.indexOf(frag) >= 0;
});
});
};
//here's your original filterTable function slightly simplified
var filterTable = function(collection, filterValue) {
if (filterValue === "") {
return collection.toJSON();
}
return collection.filter(function(data) {
return _.some(_.values(data.toJSON()), function(value) {
return partialMatch(value, filterValue);
});
});
};
Note: This method is computationally pretty inefficient, as it involves first looping over all the items in the collection, then all the fields of each item, then all words in that item value. In addition there are a few nested functions declared inside loops, so the memory footprint is not optimal. If you have a small set of data, that should be OK, but if needed, there's a number of optimizations that can be done. I might come back later and edit this a bit, if I have time.
/code samples not tested

Categories