This is my HTML snippet
<div class="well">
<h5>Test Subject ID No.:</h5>
<select id="selDataset" onchange="optionChanged(this.value)"></select>
</div>
This is how I appended options
const url = "./samples.json";
var selectDropdown = d3.select("#selDataset")
function addOptions() {
d3.json(url).then(function(data) {
data.names.forEach(name => {
var appendOption = selectDropdown.append("option").text(name)
})
})
}
addOptions()
I am now trying to add an index to each option as a value, any idea how I can do this?
D3 has an .attr method which does what you want.
var selectDropdown = d3.select("#selDataset");
function addOptions() {
d3.json(url).then(function(data) {
data.names.forEach((name, i) => {
var appendOption = selectDropdown.append("option").text(name).attr('value', i);
});
});
}
addOptions();
Related
I'm making a gallery in a modal window and when I try to set a class to the next element, it gives an error "Cannot read property 'classList' of null". How can I fix this?
HTML
<div class="card-page__imgs">
<img id="1" href="assets/img/card-page-main-img.png" class="card-page__main-img gallery-img"
src="assets/img/card-page-main-img.png" alt="Изображение">
<div class="card-page__img-group">
<img id="2" src="assets/img/card-page-img1.png" class="card-page__second-img gallery-img next-img">
<img id="3" src="assets/img/card-page-img2.png" class="card-page__second-img gallery-img">
<img id="4" src="assets/img/card-page-img3.png" class="card-page__second-img gallery-img">
</div>
</div>
JS
const galleryBtnPrev = document.querySelector('.gallery__btn_prev'),
galleryBtnNext = document.querySelector('.gallery__btn_next'),
galleryMainImg = document.querySelector('.gallery__main-img'),
galleryImages = document.querySelectorAll('.gallery-img');
const showNext = () => {
const galleryImagesArr = Array.from(galleryImages);
galleryImagesArr.forEach((el, i) => {
//if(el.classList.contains('next'))
const nextSrc = el.getAttribute('src');
if(el.classList.contains('next-img')) {
galleryMainImg.setAttribute('src', nextSrc);
el.classList.remove('next-img');
// el.classList.add('next-img');
const nextElem =el.nextElementSibling;
console.log(nextElem);
nextElem.classList.add('next-img');
return false;
}
// console.log(el, i);
});
};
You cant do const nextElem = el.nextElementSibling; because you have converted the nodeList to an array so the nextElementSibiling property doesn't work, however you can iterate through a nodeList using the forEach anyway so if you remove the const galleryImagesArr = Array.from(galleryImages); and just use galleryImages in place of galleryImagesArr It will work
EDIT
The error was from trying to read next sibling at when at the end of the array so it was returning null instead of wrapping over to the start, fixed this with simple IF statement
Like this
const galleryBtnPrev = document.querySelector('.gallery__btn_prev'),
galleryBtnNext = document.querySelector('.gallery__btn_next'),
galleryMainImg = document.querySelector('.gallery__main-img'),
galleryImages = document.querySelectorAll('.gallery-img');
const showNext = () => {
galleryImages.forEach((el, i) => {
//if(el.classList.contains('next'))
const nextSrc = el.getAttribute('src');
if(el.classList.contains('next-img')) {
//galleryMainImg.setAttribute('src', nextSrc);
el.classList.remove('next-img');
// el.classList.add('next-img');
var nextElem = el.nextElementSibling
if (nextElem === null) {
nextElem = galleryImages[0]
}
nextElem.classList.add('next-img');
return false;
}
// console.log(el, i);
});
};
showNext()
I want to fetch input elements value, they have class "features". I can access all of them
alert($('.features').length);
Correct me if I am wrong, $('.features') is an array of html input elements.But I tried
Array.isArray($('.features')) // returned false
I want to access the value of each element . How to achieve this
I tried to do one and below is the code snippet
function maintest() {
for(i = 0 ; i < 5 ; i ++ ) {
$("<input>").attr({"class":"features"}).appendTo("#mainDiv").val("input"+i);
$("<br/><br/>").appendTo("#mainDiv");
}
$("<button> Click me! </button>").click(function() {
let inputArray = [];
inputArray = $('.features');
alert(inputArray.length);
//alert( inputArray[0].val());
//what must be put here to see the data value
}).appendTo("#mainDiv");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<body onload="maintest()">
<div id="mainDiv"></div>
</body>
In javascript, setting a variable to a value overwrites the previous value. It doesn't enforce the type, so these lines:
let inputArray = [];
inputArray = $('.features');
is the same as
let inputArray = $('.features');
$() returns a jquery collection, not a javascript array; there are, of course, similarities, but it's not an "array".
To get the values out you can loop through the collection or you can use .map to extract values, eg:
var valuesArray = $('.features').map(function() {
return $(this).val();
}).toArray();
function maintest() {
for (i = 0; i < 5; i++) {
$("<input>").attr({ "class": "features" })
.appendTo("#mainDiv")
.val("input" + i);
$("<br/><br/>").appendTo("#mainDiv");
}
$("<button> Click me! </button>").click(function() {
let inputArray = $('.features');
var values = inputArray.map(function() {
return $(this).val();
}).toArray();
console.log(values);
}).appendTo("#mainDiv");
}
$(() => maintest());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="mainDiv"></div>
You could loop over the input array using jQuery $.each method.
Example:
function maintest() {
for (i = 0; i < 5; i++) {
$("<input>")
.attr({ class: "features" })
.appendTo("#mainDiv")
.val("input" + i);
$("<br/><br/>").appendTo("#mainDiv");
}
$("<button> Click me! </button>")
.click(function() {
let inputArray = [];
inputArray = $(".features");
$.each(inputArray, function(index, input) {
console.log(input.value);
});
})
.appendTo("#mainDiv");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body onload="maintest()">
<div id="mainDiv"></div>
</body>
I'm using this code right now, but I'm not really liking the way it looks.
function createPageSettingsPopup(page) {
return '<div class="form-group">' +
'<label for="page-title">Title</label>' +
'<input type="text" class="form-control" id="page-title" value="' + page.title + '">' +
'</div>'
}
Is there any alternative to write the HTML in strings to make it look better?
You could use template engines. This is at the expense of elements in the page, but the code will look much cleaner and the template easier to understand as HTML. Put the template in a script tag with type set to text/template
<script type="text/template" id="tmpl">
<div class="form-group">
<label for="page-title">Title</label>
<input type="text" class="form-control" id="page-title" value="{{pageTitle}}">
</div>
</script>
And modify your function as below. Remember to cache the template.
var template = document.getElementById('tmpl').innerHTML; // cache the HTML
function createPageSettingsPopup(page) {
// Find an replace the {{pageTitle}} with page.title, and then return the HTML string.
return template.replace(new RegExp('{{pageTitle}}', 'gi'), page.title)
}
var template = document.getElementById('tmpl').innerHTML; // cache the HTML
function createPageSettingsPopup(page) {
// Find an replace the {{pageTitle}} with page.title, and then return the HTML string.
return template.replace(new RegExp('{{pageTitle}}', 'gi'), page.title)
}
console.log(
createPageSettingsPopup({title:'Hello World'})
);
<script type="text/template" id="tmpl">
<div class="form-group">
<label for="page-title">Title</label>
<input type="text" class="form-control" id="page-title" value="{{pageTitle}}">
</div>
</script>
The above is a minimal example of a template engine, but there are great ones like mustache, handlebars.js, and pug.js
Assuming ES6 you can use backticks:
return `<div>
...
</div>`;
Or have a look at react, to manipulate your DOM, they use jsx which is really nice:
const element = <h1>Hello, world!</h1>;
In case you are using jQuery, sometimes you can do things like these:
var div = $('div').addClass('form-group');
div.append($('label').attr('for', 'page-title').text('Title');
...
Depending on your problem at hand it might also make sense to have the full html structure written up-front and then just manipulate some content and styling using js. In your example:
$('div#title').show();
$('div#title').find('label.page-title').text('Title');
You can try creating a HTML utility that creates elements, add necessary properties and the returns element.
I have created a small implementation of this utility in sample. Benefit of this is you can modify this utility to work with JSON based structure to create dynamic HTML.
Sample
function createPageSettingsPopup(page) {
var divParams = {
class: 'form-group'
}
var labelParams = {
for: 'page-title'
}
var inputParams = {
type: 'text',
class: "form-control",
id: 'page-title',
value: page.title
}
var div = utils.createMyElement('div', '', divParams);
var label = utils.createMyElement('label', 'Title', labelParams)
var input = utils.createMyElement('input', '', inputParams)
div.appendChild(label);
div.appendChild(input);
document.body.appendChild(div)
}
window.addEventListener('load', function() {
createPageSettingsPopup({
title: "foo"
})
})
// This code can be exported to another file
var utils = (function() {
function createMyElement(type, htmlString, params) {
var el = document.createElement(type);
if (htmlString)
el.innerHTML = htmlString;
addProps(el, params)
return el;
}
function addProps(el, props, key) {
if (Object.keys(props).length) {
for (var k in props) {
if (typeof(props[k]) === "object") {
addProps(el, props[k], k);
} else {
if (key) {
el[key][k] = props[k]
} else {
el[k] = props[k]
}
}
}
}
}
return {
createMyElement: createMyElement
}
})()
You can also try JSON based form.
Sample
JSFiddle
window.addEventListener('load', function() {
createPageSettingsPopup({
title: "foo"
})
})
function createPageSettingsPopup(page) {
var form = utils.createForm(getFormData(page))
document.body.appendChild(form)
}
// This can be stored in JSON file or in db and then can be fetched
function getFormData(page) {
var json = {
type: "div",
params: {
class: 'form-group',
innerHTML: "",
},
children: [{
type: 'label',
params: {
for: 'page-title',
innerHTML: "Title"
},
}, {
type: 'input',
params: {
type: 'text',
class: "form-control",
id: 'page-title',
value: page.title
}
}]
}
return json
}
// This is a generic utility and can be exported to a utility file
var utils = (function() {
function JSONBasedForm(form_json) {
var el = "";
if (form_json) {
el = createMyElement(form_json.type, form_json.params);
if (form_json.children && form_json.children.length > 0) {
form_json.children.forEach(function(child) {
var c_el = JSONBasedForm(child)
c_el && el.appendChild(c_el)
})
}
}
return el;
}
function createMyElement(type, params) {
var el = document.createElement(type);
addProps(el, params)
return el;
}
function addProps(el, props, key) {
if (Object.keys(props).length) {
for (var k in props) {
if (typeof(props[k]) === "object") {
addProps(el, props[k], k);
} else {
if (key) {
el[key][k] = props[k]
} else {
el[k] = props[k]
}
}
}
}
}
return {
createForm: JSONBasedForm
}
})()
This does not look better but is another way to create elements in JavaScript
Using the document.createElement you have more programmatic control over which attributes to set
function createPageSettingsPopup(page) {
var div = document.createElement("div");
div.className="form-group";
var label = document.createElement("label");
label.htmlFor="page-title";
label.textContent="Title";
var input = document.createElement("input");
input.type="text";
input.className="form-control";
input.id="page-title";
input.value=page.title;
label.appendChild(input);
div.appendChild(label);
return div;
}
Same in jQuery:
function createPageSettingsPopup(page) {
var $div = $("<div />",{"class":"form-group"});
$div.append(
$("<label />", {"htmlFor":"page-title").text("Title").append(
$("<input/>", { "type":"text","class":"form-control","id":"page-title"}).val(page.title)
)
);
return $div;
}
Below is my grid code, how do I get the Primary Key Value when the cell is clicked in jquery?
I have tried searching online and can't find a working example. Is there another way to get the value without using jquery or javascript?
<div id="CampaignGrid">
#(Html.EJ().Grid.Test.Test>("Grid")
...
})
.Columns(col =>
{
col.Field("iCampaign").HeaderText("Campaign").IsPrimaryKey(true).TextAlign(TextAlign.Left).Width(50).AllowEditing(false).Add();
col.Field("vCampaignName").HeaderText("Campaign Name").IsPrimaryKey(false).TextAlign(TextAlign.Left).Width(260).AllowEditing(false).Add();
})
when you are setting fields like col.Field("iCampaign"), you determine a tag with attribute name="iCampaign",which will be used in model binding.
so you can use a jquery selector like this :
$('[name = "iCampaign"]')
you can also solve your problem this way :
#(Html.EJ().Grid<EmployeeView>("MasterGrid")
.Datasource((IEnumerable<object>)ViewBag.datasource1)
.SelectedRowIndex(0)
.Columns(col =>
{
col.Field("EmployeeID").HeaderText("Employee ID").IsPrimaryKey(true).TextAlign(TextAlign.Right).Width(125).Add();
col.Field("FirstName").HeaderText("First Name").Width(100).Add();
col.Field("LastName").HeaderText("Last Name").Width(100).Add();
col.Field("Title").HeaderText("Title").Width(150).Add();
col.Field("BirthDate").HeaderText("Birth Date").TextAlign(TextAlign.Right).Width(100).Format("{0:MM/dd/yyyy}").Add();
col.Field("Country").Width(100).HeaderText("Country").Add();
})
.ClientSideEvents(eve => { eve.RowSelected("rowSelected"); })
)
<script type="text/javascript">
$(function () {
window.rowSelected = function (args) {
var employeeID = args.data.EmployeeID;
var detaildata = ej.DataManager(window.gridData).executeLocal(ej.Query().where("EmployeeID", ej.FilterOperators.equal, employeeID, false).take(10));
var gridObj = $("#DetailGrid").ejGrid("instance");
gridObj.model.dataSource = ej.DataManager(detaildata.slice(0, 5));
$("#DetailGrid").ejGrid("refreshContent");
}
});
</script>
You can try this
#(Html.EJ().Grid<EmployeeView>("MasterGrid")
.Datasource((IEnumerable<object>)ViewBag.datasource1)
.SelectedRowIndex(0)
.Columns(col =>
{
col.Field("EmployeeID").HeaderText("Employee ID").IsPrimaryKey(true).TextAlign(TextAlign.Right).Width(125).Add();
col.Field("FirstName").HeaderText("First Name").Width(100).Add();
col.Field("LastName").HeaderText("Last Name").Width(100).Add();
col.Field("Title").HeaderText("Title").Width(150).Add();
col.Field("BirthDate").HeaderText("Birth Date").TextAlign(TextAlign.Right).Width(100).Format("{0:MM/dd/yyyy}").Add();
col.Field("Country").Width(100).HeaderText("Country").Add();
})
.ClientSideEvents(eve => { eve.CellEdit("cellEdit"); })
)
<script type="text/javascript">
function cellEdit(args)
{
var pkName = args.primaryKey[0];
var pkValue = args.rowData[pkName];
}
</script>
I try to make following parts run, but always failed. The objective is: if a target in combobox is selected, the mediaId's combobox should be filled with respective values. At this moment I just emulate the values of mediaId combobox. Can anyone show me how to combine them correctly? Thx in advance.
The view Medium.cshtml:
<script src="#Url.Content("~/Scripts/PartialLoad.js")" type="text/javascript"></script>
<div class="editor-label">
#Html.LabelFor(model => model.Files[i].TargetId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Files[i].PTargetId, (ViewData["targets"] as SelectList).MakeSelection(Model.Files[i].PTargetId))
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Files[i].MediaId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Files[i].MediaId, (ViewData["mediaIds"] as SelectList).MakeSelection(1))
</div>
The javascript partialload.js
$(document).ready(function () {
$("#targets").change(function () { GetMValues("#targets", "#mediaIds"); });
});
function ClearDrop(objSource) {
$(objSource).empty();
}
function GetMValues(objSource, objDest) {
var url = '/GetMValues/';
$.getJSON(url, { id: $(objSource).val() },
function (data) {
ClearDrop(objDest); $.each(data, function (index, optionData) {
$(objDest).append("<option value='" + optionData.Value + "'>" + optionData.Text + "</option>");
});
});
}
The homecontroller.cs
public ActionResult GetMValues(String id)
{
int myId = 0;
int.TryParse(id, out myId);
var mediumIds = new List<long>();
int max = myId + 3;
// just to emulate the data in the list
for ( long l = 1 ; l < max ; l++ ){
mediumIds.Add(l);
}
var select = new SelectList(mediumIds, "PTargetId", "TargetId");
return Json(select, JsonRequestBehavior.AllowGet); //allow get needed to allow get calls
}
Here you are using an id selector for the dropdownlist: $("#targets") but your dropdown doesn't seem to have such id. Maybe you want to assign it an id or a class:
#Html.DropDownListFor(
model => model.Files[i].PTargetId,
(ViewData["targets"] as SelectList).MakeSelection(Model.Files[i].PTargetId),
new { id = "targets" }
)
But because this seems to be repeated and you cannot have multiple elements with the same id a class selector is probably more appropriate:
#Html.DropDownListFor(
model => model.Files[i].PTargetId,
(ViewData["targets"] as SelectList).MakeSelection(Model.Files[i].PTargetId),
new { #class = "targets" }
)
and then:
$(document).ready(function () {
$(".targets").change(function () {
...
});
});
Same remark obviously for #mediaIds.