Get a list from javascript object - javascript

I am a new beginner in javascript and I am trying to figure out how to get a list from this object components.
I only need to select js keys from mndatory
var components = {
mandatory: {
alert: {
js: ['./bootstrap/js/alert.js'],
css: ['./bootstrap/css/alert.css', './bootstrap/css/alert2.css'],
},
button: {
js: ['./bootstrap/js/button.js'],
css: ['./bootstrap/css/button.css'],
},
dropdown: {
js: ['./bootstrap/js/dropdown.js'],
css: ['./bootstrap/css/dropdown.css'],
},
},
optional: {
carousel: {
js: ['./bootstrap/js/carousel.js'],
css: ['./bootstrap/css/carousel.css'],
},
modal: {
js: ['./bootstrap/js/modal.js'],
css: ['./bootstrap/css/modal.css'],
},
},
};
So the result will be the selection of only the js keys:
[
'./bootstrap/js/alert.js',
'./bootstrap/js/button.js',
'./bootstrap/js/dropdown.js'
]
I really appreciate your help.

You can use a for-in loop:
for (const property in components.mandatory) {
console.log(property.js);
}
You can probably take it from here.
Documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

Something like the below code should help you. Please try to understand how the below code is working.
var components = {
mandatory: {
alert: {
js: ['./bootstrap/js/alert.js'],
css: [
'./bootstrap/css/alert.css',
'./bootstrap/css/alert2.css'
]
},
button: {
js: ['./bootstrap/js/button.js'],
css: ['./bootstrap/css/button.css']
},
dropdown: {
js: ['./bootstrap/js/dropdown.js'],
css: ['./bootstrap/css/dropdown.css']
}
},
optional: {
carousel: {
js: ['./bootstrap/js/carousel.js'],
css: ['./bootstrap/css/carousel.css']
},
modal: {
js: ['./bootstrap/js/modal.js'],
css: ['./bootstrap/css/modal.css']
}
}
}
var array = [components.mandatory.alert.js, components.mandatory.button.js, components.mandatory.dropdown.js].flat();
console.log(array)

You can iterate over the attributes and then add the js elements to a global list as follows:
$(document).ready(function() {
var components = {
mandatory: {
alert: {
js: ['./bootstrap/js/alert.js'],
css: [
'./bootstrap/css/alert.css',
'./bootstrap/css/alert2.css'
]
},
button: {
js: ['./bootstrap/js/button.js'],
css: ['./bootstrap/css/button.css']
},
dropdown: {
js: ['./bootstrap/js/dropdown.js'],
css: ['./bootstrap/css/dropdown.css']
}
},
optional: {
carousel: {
js: ['./bootstrap/js/carousel.js'],
css: ['./bootstrap/css/carousel.css']
},
modal: {
js: ['./bootstrap/js/modal.js'],
css: ['./bootstrap/css/modal.css']
}
}
};
let mandatory = components.mandatory;
let list = [];
for (var key in mandatory) {
if (mandatory.hasOwnProperty(key)) {
let current = mandatory[key]['js'];
if(current){
for(var i = 0; i < current.length; i++)
list.push(current[i]);
}
}
}
console.log(list)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Well, as others have answered without waiting for effort from the OP, let me throw my suggestion out there:
const extractJs = components =>
Object .values (components .mandatory) .flatMap (x => x .js)
const components = {mandatory: {alert: {js: ["./bootstrap/js/alert.js"], css: ["./bootstrap/css/alert.css", "./bootstrap/css/alert2.css"]}, button: {js: ["./bootstrap/js/button.js"], css: ["./bootstrap/css/button.css"]}, dropdown: {js: ["./bootstrap/js/dropdown.js"], css: ["./bootstrap/css/dropdown.css"]}}, optional: {carousel: {js: ["./bootstrap/js/carousel.js"], css: ["./bootstrap/css/carousel.css"]}, modal: {js: ["./bootstrap/js/modal.js"], css: ["./bootstrap/css/modal.css"]}}};
console .log (extractJs (components))
We first take the mandatory property, then use Object .values to extract the values of each of its properties. We flatMap over the resulting objects, combining their .js properties. The flatMap call will flatten the resulting arrays into one as it goes.
You might want to add some checking along the way. Is components actually an object?, Does it have an object mandatory property?, etc. I leave that to you.

var result = []
Object.keys(components.mandatory).forEach(x => {
components.mandatory[x].js.forEach(y => result.push(y));
})

Related

Can Javascript read a title tag from a HTML doc and ignore that value in an array?

I am trying to create a "random article" menu with Javascript at the bottom of blog posts.
I am wondering if there is a way to get the script to read the of the current article so I can omit that from the array and not have the article link to itself.
I get that I'll have to change the way the array data is stored, just need to know if I can make JS read the HTML tag.
Thanks!
//array is [<title>, <img src>]
var arts = [
["Santorini", "santo1_450h"],
["Penang", "penang1"],
["Porto", "Porto6_450h"],
["Crete", "Crete5"],
["Langkawi", "langkawi2"],
["Singapore", "singapore1"]
];
var clone = [];
function shuffle(array) {
//shuffles the array
return clone;
}
shuffle(arts);
function createRandArts() {
//creates a bunch of HTML content
}
createRandArts();
You can use document.title to get the title of the current page and then loop through your array and remove it
Here is how you read a title tag
var list = document.getElementsByTagName("TITLE")[0]
Yes you can use JS to read the document title, and then loop through your array, omitting that title if found.
Here's an example using an array of objects instead:
var arts = [
{
title: "Santorini",
src: "santo1_450h"
},
{
title: "Penang",
src: "penang1"
},
{
title: "Porto",
src: "Porto6_450h"
},
{
title: "Crete",
src: "Crete5"
},
{
title: "Langkawi",
src: "langkawi2"
},
{
title: "Singapore",
src: "singapore1"
}
];
function shuffle(array) {
let clone = [];
clone = arts.filter(e => e.title !== document.title);
//shuffle clone here
return clone;
}

Highlight selected jsGrid row

I found this example which highlights a row after it has been selected but the problem with it is that it keeps the previous row(s) highlighted after another one has been selected.
Here's part of the code
//js
rowClick: function(args) {
var $row = this.rowByItem(args.item);
$row.toggleClass("highlight");
},
//css
tr.highlight td.jsgrid-cell {
background-color: green;
}
I can't find a solution to unhighlight the previously selected row
A little late to the party on this one, however the accepted answer by #Narenda didn't completely solve my problem. This may help someone else that stumbles across this later.
If you need a single select only, here's a way of doing it:
Extend the jsGrid plugin with a method to find a row by index:
jsGrid.Grid.prototype.rowByIndex = function(arg){
//this._content.find("tr")[arg] returns a DOM element instead of a jQuery object
//Pass the DOM element to the find method to get a jQuery object representing it
return this._content.find(this._content.find("tr")[arg]);
};
Modify the rowClick function in #Narenda's answer:
rowClick: function ( args ) {
//Deselect all rows
for(var i = 0; i<this.data.length; i++){
this.rowByIndex(i).removeClass("jsgrid-highlight-row");
}
//Everything else as per the previous answer
var $row = this.rowByItem(args.item),
selectedRow = $("#jsGrid").find('table tr.jsgrid-highlight-row');
if (selectedRow.length) {
selectedRow.toggleClass('jsgrid-highlight-row');
};
$row.toggleClass("jsgrid-highlight-row");
//Any other code to run on item click
}
And add some CSS. This mimics the row hover in the default theme:
tr.jsgrid-highlight-row td.jsgrid-cell {
background:#c4e2ff;
border-color:#c4e2ff;
}
You can achieve by this following steps
First on row click you need to get selected row like this
var selectedRow = $("#jsGrid").find('table tr.highlight').
Then you can use
selectedRow.toggleClass('highlight') or selectedRow.removeClass('highlight')
DEMO
$("#jsGrid").jsGrid({
width: "100%",
height: "auto",
paging: false,
//for loadData method Need to set auto load true
autoload: true,
noDataContent: "Directory is empty",
controller: {
loadData: function(filter) {
var data = [{
nickname: "Test",
email: "t#gmail.com"
}, {
nickname: "Test 1",
email: "t1#gmail.com"
}, {
nickname: "Test 2",
email: "t2#gmail.com"
}, {
nickname: "Test 3",
email: "t3#gmail.com"
}];
return data;
}
},
rowClick: function(args) {
var $row = this.rowByItem(args.item),
selectedRow = $("#jsGrid").find('table tr.highlight');
if (selectedRow.length) {
selectedRow.toggleClass('highlight');
};
$row.toggleClass("highlight");
},
fields: [{
name: "nickname",
type: "text",
width: 80,
title: "Name"
}, {
name: "email",
type: "text",
width: 100,
title: "Email Address",
readOnly: false
}]
});
tr.highlight td.jsgrid-cell {
background-color: green;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid-theme.min.css" />
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jsgrid/1.5.3/jsgrid.min.js"></script>
<div id="jsGrid"></div>
If you came looking for a solution in which only 1 line is selected and which also deselects the same line, here is the solution:
selectedVal = null;
$(document).ready(function(){
jsGrid.Grid.prototype.rowByIndex = function(arg) {
//this._content.find("tr")[arg] returns a DOM element instead of a jQuery object
//Pass the DOM element to the find method to get a jQuery object representing it
return this._content.find(this._content.find("tr")[arg]);
};
});
rowClick: function (args) {
selectedVal = args.item;
let $row = this.rowByItem(args.item);
if ($row.hasClass("highlight") === false) {
//Deseleciona todas as linhas
for (let i = 0; i < this.data.length; i++) {
this.rowByIndex(i).removeClass("highlight");
}
$row.toggleClass("highlight");
} else {
selectedVal = null;
$row.toggleClass("highlight");
}
console.log(selectedVal);
}

Animating/Referencing dynamic elements with Jquery

I have a number of dynamically created elements that I want to later animate. I know that dynamic elements can by referenced using:
$(document).on(event, selector, cb)
but I am not sure how to implement this with animate. Here is my code if it helps. "state.headings" and "state.text" reference the dynamic elements
var state = {
sm: () => {return $(window).width() < "576"},
blocks: [
$("#first-block"),
$("#second-block")
],
pairs: [
$("#first-pair"),
],
headings: [
$("#first-heading"),
$("#second-heading"),
],
text: [
$("#first-text"),
$("#second-text"),
],
watching: 0,
}
$(window).on("scroll", () => {
if (state.sm()) {
if (isInViewport(state.blocks[state.watching])) {
if (state.headings[state.watching].css("right") !== "0px") {
state.headings[state.watching].animate({
right: "0px"
})
state.text[state.watching].animate({
left: "0px"
}, () => {
if (state.watching < state.blocks.length -1){
state.watching++
}
})
}
}
} else {
//handle animations for larger devices
}
})
I was able to get around it by setting my selectors to regular strings and using
$(document.getElementById(selector)).animate()
but I am still interested to know if jQuery provides its own solution.

What is the best way to shorten this code?

Using the DRY methodology, I was wondering what could be the best way this code could be shorten. It seems to me there is too much repetition in there.
function back(){
$('.back').click(function(){
if($(this).hasClass('back_3')){
$('.screen3').addClass('hidden');
$('.screen1').removeClass('hidden');
}else if ($(this).hasClass('back_2')){
$('.screen2').addClass('hidden');
$('.screen1').removeClass('hidden');
}else if($(this).hasClass('back_4')){
$('.screen4').addClass('hidden');
$('.screen3').removeClass('hidden');
}else if($(this).hasClass('back_5')){
$('.screen5').addClass('hidden');
$('.screen3').removeClass('hidden');
}else if($(this).hasClass('back_6')){
$('.screen6').addClass('hidden');
$('.screen3').removeClass('hidden');
}
});
}
Best way to DRYify this code is to use data-* attributes to link the button to what to hide/show
eg (for first if branch)
<button class="back" data-hide=".screen3" data-show=".screen1">Back_3</button>
and then this
$('.back').click(function(){
var $this = $(this);
$($this.data("hide")).addClass("hidden");
$($this.data("show")).removeClass("hidden");
});
Same handler works for any .back button with data-hide and data-show attributes.
Simpy extract the id of the class, then hide/show the respective classes:
$('.back').click(function(){
var id = this.className.split(" ").find(clss => clss.includes("back_")).split("_")[1];
$(".screen"+id).addClass("hidden");
$(".screen"+id>3?3:1).removeClass("hidden");
});
I would do something like this (not tested):
var arrScreens=[
{hC:"back_3",screenShow:".screen3",screenHide:".screen1"]},
{hC:"back_2",screenShow:".screen2",screenHide:".screen1"]},
]
function back(){
$('.back').click(function(){
var $this=$(this);
$(arrScreens).each(function(i,obj) {
if($this.hasClass(obj.hC)) {
$(obj.screenShow).addClass('hidden');
$(obj.screenHide).removeClass('hidden');
return false;
}
});
});
}
This is what I would have done in your case.
const routes = [
{id: 'back_3', hide: '.screen3', show: '.screen1' },
{id: 'back_2', hide: '.screen2', show: '.screen1' },
{id: 'back_4', hide: '.screen4', show: '.screen3' },
{id: 'back_5', hide: '.screen5', show: '.screen3' },
{id: 'back_6', hide: '.screen6', show: '.screen3' },
];
function back() {
const hiddenCls = 'hidden';
const $back = $('.back');
return $back.click(event => {
event.preventDefault();
for(const route of routes) {
const {id, hide, show} = route;
if($(event.currentTarget).hasClass(id)) {
$(hide).addClass(hiddenCls);
$(show).removeClass(hiddenCls);
break;
}
}
});
}

Ember component's template issue with jQuery sortable

I'm trying to create a simple Ember component that wraps jQuery UI Sortable plugin. Unfortunately I have an issue with component's template when sortable is cancelled and model is updated manually. It looks like the DOM does not reflect the state of the model. I'm not able to find why.
I've created JS Bin to present this issue. When you change item position, the first one in the group should be removed. Unfortunately it works randomly.
What's wrong with this code?
Here is your JS Bin sortable component:
App.MyListComponent = Ember.Component.extend({
tagName: 'ul',
didInsertElement() {
let opts = {};
opts.update = this.updateList.bind(this);
this.$().sortable(opts);
},
updateList() {
this.$().sortable('cancel');
Ember.run.next(() => {
this.get('content').removeAt(0);
});
}
});
And then this is your JS Bin updated with code from the ember-ui-sortable repo to the following:
App.MyListComponent = Ember.Component.extend({
tagName: 'ul',
uiOptions: [
'axis',
'containment',
'cursor',
'cursorAt',
'delay',
'disabled',
'distance',
'forceHelperSize',
'forcePlaceholderSize',
'grid',
'handle',
'helper',
'opacity',
'placeholder',
'revert',
'scroll',
'scrollSensitivity',
'scrollSpeed',
'tolerance',
'zIndex'
],
destroySortable: Ember.on('willDestroyElement', function() {
this.$().sortable('destroy');
}),
initSortable: Ember.on('didInsertElement', function () {
let opts = {};
['start', 'stop'].forEach((callback) => {
opts[callback] = Ember.run.bind(this, callback);
});
this.$().sortable(opts);
this.get('uiOptions').forEach((option) => {
this._bindSortableOption(option);
});
}),
contentObserver: Ember.observer('content.[]', function () {
Ember.run.scheduleOnce('afterRender', this, this._refreshSortable);
}),
move(oldIndex, newIndex) {
let content = this.get('content');
let mutate = this.getWithDefault('mutate', true);
let item = content.objectAt(oldIndex);
if (content && mutate) {
content.removeAt(oldIndex);
content.insertAt(newIndex, item);
}
if(!mutate){
this.attrs.moved(item, oldIndex, newIndex);
}
},
start(event, ui) {
ui.item.data('oldIndex', ui.item.index());
},
stop(event, ui) {
const oldIndex = ui.item.data('oldIndex');
const newIndex = ui.item.index();
this.move(oldIndex, newIndex);
},
_bindSortableOption: function(key) {
this.addObserver(key, this, this._optionDidChange);
if (key in this) {
this._optionDidChange(this, key);
}
this.on('willDestroyElement', this, function() {
this.removeObserver(key, this, this._optionDidChange);
});
},
_optionDidChange(sender, key) {
this.$().sortable('option', key, this.get(key));
},
_refreshSortable() {
if (this.isDestroying) { return; }
this.$().sortable('refresh');
}
});
As you'll see, there is quite a bit extra going on versus your original, so you can have a look at what you missed and hopefully this helps you.
It might be a good idea to install that component addon via ember-cli, but also have a look at competing solutions like ember-sortable and others first by using something like ember-observer.

Categories

Resources