I have two arrays like below and implemented the iterations using old for loop approach. However, how can I get the same in forEach().
var questions =['your name', 'SkillSet', 'exp']
var answers =['King', 'Nodejs', '5']
for(let i = 0; i<questions.length; i++){
htmlobj += '<tr><th>'+questions[i]+'</th></tr>'
htmlobj += '<tr><th>'+answers[i]+'</th></tr>'
}
I pretty much consider a .forEach() loop to be obsolete these days because a for loop is so much more flexible. With modern Javascript, you can use for/of and still get value and index:
const questions =['your name', 'SkillSet', 'exp']
const answers =['King', 'Nodejs', '5']
let htmlobj = "";
for (const [index, question] of questions.entries()) {
htmlobj += `<tr><th>${question}</th></tr><tr><th>${answers[index]}</th></tr>`;
}
console.log(htmlobj);
While the additional flow control advantages of a for loop aren't being used here, they are very useful in many other circumstances and the regular for loop doesn't incur the function overhead of calling a callback function for every iteration of the loop.
And, if you want one row for each question and answer, you would need to change the HTML like this:
const questions =['Your Name', 'SkillSet', 'Exp']
const answers =['King', 'Nodejs', '5']
let htmlobj = "";
for (const [index, question] of questions.entries()) {
htmlobj += `<tr><th>${question}</th><th>${answers[index]}</th></tr>`;
}
document.getElementById("result").innerHTML = htmlobj;
table {
border-collapse: collapse;
}
th {
text-align: left;
border-bottom: 1px solid;
margin: 0;
padding: 10px;
}
<table id=result></table>
let htmlobj = ""
questions.forEach((el, index) => {
htmlobj += '<tr><th>'+el+'</th></tr>'
htmlobj += '<tr><th>'+answers[index]+'</th></tr>'
})
Related
Has somebody already achieved to display a chart, not based on timeseries (like the chart from the dashboard), but on data passed to it?
I wonder if it is, perhaps, possible to use a template to do that? But I've no clue how to do it. If someone has a small example, it would be great.
I've found a solution, using some code sample from the library...
The link between msg.payload and data is still missing, but not far away
<style>
#chart svg {
width: 800px;
height: 600px;
}
</style>
<h3>test</h3>
<div id="chart">
<svg></svg>
</div>
<script src="https://raw.githubusercontent.com/novus/nvd3/master/build/nv.d3.js"></script>
<script>
(function(scope) {
console.log('Position 1');
console.dir(scope);
console.log(scope.msg);
scope.$watch('msg.payload', function(data) {
console.log('Position 2');
console.dir(data);
});
})(scope);
function data() {
var sin = [],
cos = [];
for (var i = 0; i < 100; i++) {
sin.push({x: i, y: Math.sin(i/10)});
cos.push({x: i, y: .5 * Math.cos(i/10)});
}
return [
{
values: sin,
key: 'normal',
color: '#ff7f0e'
},
{
values: cos,
key: 'defect',
color: '#2ca02c'
}
];
}
nv.addGraph(function() {
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
;
chart.xAxis
.axisLabel('frequence')
.tickFormat(d3.format(',r'))
;
chart.yAxis
.axisLabel('amplitude')
.tickFormat(d3.format('.02f'))
;
d3.select('#chart svg')
.datum(data())
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
</script>
I'm new to Knockout JS and I find this library very powerful, but quite hard to understand sometimes. The documentation is hudge, but it's always (too) small code snippets, so it's difficult to have the big picture, unless your coding style & philosophy paradigm are the same as KO developers.
I come from angular world, and I'm used to have an array where each item is an object with properties (id, name, etc). When I click a button, I "send" this object to a new component that will render it in a form.
I'm sure I'm missing something obvious, but I don't understand how to make things work, even with plugins like ko.mapping and ko.postbox.
Does anyone can help me to find the solution? In the working code above, I've posted my 3 very specific questions in the javascript area.
EDIT: I answered to them, but I don't know if it's a best practice or not.
var
// User class to give to each property the observable capacity
User = function (rawData) {
var self = this,
data = rawData || {};
self.id = ko.observable(data.id);
self.name = ko.observable(data.name);
},
// List component. initially in a separate file
// (small modifs so all can be in the same file for this demo)
cmplist = {
viewModel: function () {
var self = this;
self.users = ko.observableArray([
new User({id: 1, name: 'John'}),
new User({id: 2, name: 'Jack'}),
new User({id: 3, name: 'Smith'})
]);
// #ANSWER 1: initialize postbox event
self.user = ko.observable(new User()).publishOn('userEdit');
self.showEdit = function (user) {
// #QUESTION 1: how do I send this object to the
// users-form component. ko.postbox?
// #ANSWER 1: change the observable
self.user(user);
console.log('show', user);
};
},
template: ''
+ '<ul data-bind="foreach: users">'
+ '<li>'
+ '<button data-bind="click: $parent.showEdit">Edit</button>'
+ ' <span data-bind="text: name"></span>'
+ '</li>'
+ '</ul>'
},
// Form component, initially in a separate file
// (small modifs so all can be in the same file for this demo)
cmpform = {
viewModel: function () {
var self = this;
// #QUESTION 2: how do I recept the object sent by the
// list?
// #ANSWER 2: make the observable subscribe to event
self.user = ko.observable(new User()).subscribeTo('userEdit');
self.save = function () {
// #QUESTION 3: how do I notify the users-list cmp
// that object has changed? ko.postbox?
window.alert('save ' + ko.toJSON(self.user()));
console.log('save');
};
},
// #ANSWER 2: call user() with parenthesis to access properties
template: ''
+ '<form>'
+ '<p>Edit user <span data-bind="text: user().name"></span> '
+ 'with id <span data-bind="text: user().id"></span></p>'
+ '<input data-bind="textInput: user().name" />'
+ '<button data-bind="click: save">Save</button>'
+ '</form>'
};
// KO bootstrap, initially in a 3rd file
// (small modifs so all can be in the same file for this demo)
ko.components.register('users-list', cmplist);
ko.components.register('users-form', cmpform);
ko.applyBindings({});
ul {
border: 1px solid blue;
list-style: none;
float: left;
}
li {
border: 1px solid green;
}
form {
border: 1px solid red;
float: right;
margin-top: 20px;
}
ul, li, form {
padding: 5px;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-postbox/0.5.2/knockout-postbox.min.js"></script>
</head>
<body>
<users-list></users-list>
<users-form></users-form>
</body>
</html>
I am using node/npm blessed to create a screen to monitor a particular application and I want the monitor tool to look/act like linux top. The problem I have, which I think is relatively simple (but I cant find the answer anywhere), is to have blessed clear the screen at startup as well as at particular points based upon user input.
Right now I can use blessed to paint the screen properly (sample program below), but the problem is I need the screen to be cleared at startup (right now the first line of output just appends right after you start up the program):
var blessed = require('blessed');
var screen = blessed.screen(),
body = blessed.box({
top: 0,
left: 0,
width: '100%',
height: '100%',
tags: true
});
var items = [];
screen.append(body);
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
function log(text) {
items.push(text);
var MAX = 10;
if( items.length > MAX+1 ){
items.shift();
}
for (var i=1; i<MAX; i++){
body.setLine(i, items[i]);
}
screen.render();
}
function status(text) {
body.setLine(0, text );
screen.render();
}
var counter = 1;
setInterval(function() {
status((new Date()).toISOString());
log('Line number: ' + (counter++));
}, 1000);
For completeness, the solution to this question is provided below, and is very simple. To clear the screen, issue the following code at the start of the program:
screen.render();
The sample program that I referenced in the original post can be modified as follows and now works:
var blessed = require('blessed');
var screen = blessed.screen(),
body = blessed.box({
top: 0,
left: 0,
width: '100%',
height: '100%',
tags: true
});
// The following line clears the screen
screen.render();
:
:
I am trying to scrape some data from a shopping site Express.com. Here's 1 of many products that contains image, price, title, color(s).
<div class="cat-thu-product cat-thu-product-all item-1">
<div class="cat-thu-p-cont reg-thumb" id="p-50715" style="position: relative;"><img class="cat-thu-p-ima widget-app-quickview" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_900/i81?$dcat191$" alt="ROCCO SLIM FIT SKINNY LEG CORDUROY JEAN"><img id="widget-quickview-but" class="widget-ie6png glo-but-css-off2" src="/assets/images/but/cat/but-cat-quickview.png" alt="Express View" style="position: absolute; left: 50px;"></div>
<ul>
<li class="cat-cat-more-colors">
<div class="productId-50715">
<img class="js-swatchLinkQuickview" title="INK BLUE" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_900_s/i81?$swatch$" width="16" height="6" alt="INK BLUE">
<img class="js-swatchLinkQuickview" title="GRAPHITE" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_924_s/i81?$swatch$" width="16" height="6" alt="GRAPHITE">
<img class="js-swatchLinkQuickview" title="MERCURY GRAY" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_930_s/i81?$swatch$" width="16" height="6" alt="MERCURY GRAY">
<img class="js-swatchLinkQuickview" title="HARVARD RED" src="http://t.express.com/com/scene7/s7d5/=/is/image/expressfashion/25_323_2516_853_s/i81?$swatch$" width="16" height="6" alt="HARVARD RED">
</div>
</li>
<li class="cat-thu-name"><a href="/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro" onclick="var x=".tl(";s_objectID="http://www.express.com/rocco-slim-fit-skinny-leg-corduroy-jean-50715-647/control/show/3/index.pro_2";return this.s_oc?this.s_oc(e):true">ROCCO SLIM FIT SKINNY LEG CORDUROY JEAN
</a></li>
<li>
<strong>$88.00</strong>
</li>
<li class="cat-thu-promo-text"><font color="BLACK" style="font-weight:normal">Buy 1, Get 1 50% Off</font>
</li>
</ul>
The very naive and possibly error-prone approach I've done is to first to grab all prices, images, titles and colors:
var price_objects = $('.cat-thu-product li strong');
var image_objects = $('.cat-thu-p-ima');
var name_objects = $('.cat-thu-name a');
var color_objects = $('.cat-cat-more-colors div');
Next, I populate arrays with the data from DOM extracted using jsdom or cheerio scraping libraries for node.js. (Cheerio in this case).
// price info
for (var i = 0; i < price_objects.length; i++) {
prices.push(price_objects[i].children[0].data);
}
// image links
for (var i = 0; i < image_objects.length; i++) {
images.push(image_objects[i].attribs.src.slice(0, -10));
}
// name info
for (var i = 0; i < name_objects.length; i++) {
names.push(name_objects[i].children[0].data);
}
// color info
for (var i = 0; i < color_objects.length; i++) {
colors.push(color_objects[i].attribs.src);
}
Lastly, based on the assumption that price, title, image and colors will match up create a product object:
for (var i = 0; i < images.length; i++) {
items.push({
id: i,
name: names[i],
price: prices[i],
image: images[i],
colors: colors[i]
});
}
This method is slow, error-prone, and very anti-DRY. I was thinking it would be nice if we could grab $('.cat-thu-product') and using a single for-loop extract relevant information from a single product a time.
But have you ever tried traversing the DOM in jsdom or cheerio? I am not sure how anyone can even comprehend it. Could someone show how would I use this proposed method of scraping, by grabbing $('.cat-thu-product') div element containing all relevant information and then extract necessary data?
Or perhaps there is a better way to do this?
I would suggest still using jQuery (because it's easy, fast and secure) with one .each example:
var items = [];
$('div.cat-thu-product').each(function(index, productElement) {
var product = {
id: $('div.cat-thu-p-cont', productElement).attr('id'),
name: $('li.cat-thu-name a', productElement).text().trim(),
price: $('ul li strong', productElement).text(),
image: $('.cat-thu-p-ima', productElement).attr('src'),
colors: []
};
// Adding colors array
$('.cat-cat-more-colors div img', productElement).each(function(index, colorElement) {
product.colors.push({name: $(colorElement).attr('alt'), imageUrl: $(colorElement).attr('src')});
});
items.push(product);
});
console.log(items);
And to validate that you have all the required fields, you can write easilly validator or test. But if you are using different library, you still should loop through "div.cat-thu-product" elements.
Try node.io https://github.com/chriso/node.io/wiki
This will be a good approach of doing what you are trying to do.
using https://github.com/rc0x03/node-promise-parser
products = [];
pp('website.com/products')
.find('div.cat-thu-product')
.set({
'id': 'div.cat-thu-p-cont #id',
'name': 'li.cat-thu-name a',
'price': 'ul li strong',
'image': '.cat-thu-p-ima',
'colors[]': '.cat-cat-more-colors div img #alt',
})
.get(function(product) {
console.log(product);
products.push(product);
})
hi can you check over what i've tried to do with the multiple favorites? I can't seem to get it working...
var title_regexp = [/^.+- Wikipedia, the free encyclopedia$/, /^.+- Stack Overflow$/, /^.+- W3Schools$/];
var addr_regexp = [/^\w+\.wikipedia\.org\/.*$/, /^stackoverflow\.com\/.*$/, /^www\.w3schools\.com\/.*$/];
var mark_style = 'background-color: #CCFF99 !important; padding: 0.5em; -moz-border-radius: 0.5em';
var match_pattern = [3,3,3];
and the rest is untouched.
thank you for your help
the original document is at http://userscripts.org/scripts/show/55641
According to the docs and code for that script, match_pattern should be an integer, not an array. :
var match_pattern = 3;