I am looking to pull data from a job board API. I'd like to have headings for the departments (pulled from JSON level 1) and under each department the current open positions (JSON level 2). I have tinkered with this 50 different ways and ran through all the related articles I can find, but just can't quite get the dominoes to fall in my brain.
Update
I have gotten pretty close, but I'm obviously missing how to loop this correctly. It repeats every department and job instead of nesting all of the jobs under the department header once.
Fiddle to see where I am at - https://jsfiddle.net/swampfox/f6jv204x/#&togetherjs=GjcUL090zr
$(function() {
$.ajax({
url: 'https://boards-api.greenhouse.io/v1/boards/agilityrobotics/departments',
data: {
check: 'one'
},
dataType: 'jsonp',
success: function(result) {
$.each(result, function(key, value) {
for (var i = 0; i < value.length; i++) {
$.each(value[i].jobs, function(k, v) { // Second Level into Jobs
$('#jsonpResult').append(
$('<h3>' + value[i].name + '</h3><p class="cat"><a class="joblink" href="' + v.absolute_url + '"> ' + v.title + '</a></p>')
);
});
}
});
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="jsonpResult"></div>
The main issue is that you output the h3 for each job, but it should only be output once per iteration of the outer loop (not the inner loop).
I would also use more jQuery style for creating the elements, and I would use async/await to flatten a bit the "callback hell".
$(async function() {
let {departments} = await $.getJSON('https://boards-api.greenhouse.io/v1/boards/agilityrobotics/departments');
$("#jsonpResult").append(
departments.flatMap(({name, jobs}) => [
$("<h3>").text(name),
...jobs.map(({absolute_url: href, title}) =>
$("<p>", { "class": "cat" }).append(
$("<a>", { href, "class": "joblink" }).text(title)
)
)
])
);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="jsonpResult"></div>
To exclude departments for which there are no jobs:
$(async function() {
let {departments} = await $.getJSON('https://boards-api.greenhouse.io/v1/boards/agilityrobotics/departments');
$("#jsonpResult").append(
departments.flatMap(({name, jobs}) => jobs.length ? [
$("<h3>").text(name),
...jobs.map(({absolute_url: href, title}) =>
$("<p>", { "class": "cat" }).append(
$("<a>", { href, "class": "joblink" }).text(title)
)
)
] : [])
);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="jsonpResult"></div>
Related
How i can filter my JSON object with array.
FIDDLE
This is an sample of my json object and code, i want to filter final render HTML by selected checkbox.
Thanks for your help
function init(arr){
var li = '';
$.each(jsn, function (key, value) {
if (arr.length == 0) {
li += '<li>' + jsn[key].name + '</li>';
}else{
$(arr).each(function (i, v) {
// this section must be filter "pack's" but i can't writ correct query
li += '<li>' + jsn[key].name + '</li>';
});
};
$('#container').html(li);
})
}
var CheckArr = new Array();
init(CheckArr);
$('#btnFilter').click(function(){
var CheckArr = new Array();
$('input[type=checkbox]').each(function () {
if ($(this).is(':checked')) {
CheckArr.push($(this).attr('value'))
}
});
init(CheckArr);
First of all, you have to verify length of array outside of init function. (for case when function is called for first time).Then, you need to iterate your checkboxes array and search every item in your json array(called jsn) to verify condition you need.
Here is solution:
$(document).ready(function(){
var jsn = [
{
"name":"pack01",
"caplessthan100mb":"False",
"cap100to500mb":"True",
"cap500mbto2g":"False",
"cap2gto10g":"False"
},
{
"name":"pack02",
"caplessthan100mb":"True",
"cap100to500mb":"False",
"cap500mbto2g":"False",
"cap2gto10g":"False"
},
{
"name":"pack03",
"caplessthan100mb":"False",
"cap100to500mb":"False",
"cap500mbto2g":"False",
"cap2gto10g":"True"
},
{
"name":"pack04",
"caplessthan100mb":"False",
"cap100to500mb":"False",
"cap500mbto2g":"True",
"cap2gto10g":"False"
},
{
"name":"pack05",
"caplessthan100mb":"False",
"cap100to500mb":"False",
"cap500mbto2g":"False",
"cap2gto10g":"True"
},
{
"name":"pack06",
"caplessthan100mb":"True",
"cap100to500mb":"False",
"cap500mbto2g":"False",
"cap2gto10g":"False"
},
{
"name":"pack07",
"caplessthan100mb":"False",
"cap100to500mb":"False",
"cap500mbto2g":"False",
"cap2gto10g":"True"
}
];
function init(arr){
var li = '';
if(arr.length==0)
{
$.each(jsn, function (key, value) {
li+= '<li>' + jsn[key].name + '</li>';
});
}
else{
$(arr).each(function (i, v) {
$.each(jsn, function (key, value) {
if(jsn[key][v]=="True")
li+= '<li>' + jsn[key].name + '</li>';
});
});
}
$('#container').html(li);
}
var CheckArr = new Array();
init(CheckArr);
$('#btnFilter').click(function(){
var CheckArr = new Array();
$('input[type=checkbox]').each(function () {
if ($(this).is(':checked')) {
CheckArr.push($(this).attr('value'))
}
});
init(CheckArr);
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li><input type="checkbox" value="caplessthan100mb">caplessthan100mb</li>
<li><input type="checkbox" value="cap100to500mb">cap100to500mb</li>
<li><input type="checkbox" value="cap500mbto2g">cap500mbto2g</li>
<li><input type="checkbox" value="cap2gto10g">cap2gto10g</li>
<li><input type="button" id="btnFilter" value="Filter"></li>
</ul>
<br />
<ul id="container">
</ul>
There are quite a few things in your code that could use improvement so I've taken the liberty of largely rewriting it (see jsFiddle link below).
1) First thing is in your data (jsn) you are using "False" and "True" instead of false and true. That'll make it hard to write your filter condition because true != "True".
2) It's quite hard to debug your code because the variable names aren't very meaningful. I'd highly recommend putting some energy into improving your variable names especially when code isn't working.
For example:
packsData instead of jsn
checkedBoxes instead of arr
3) If you try to filter within the .each() below you'll run into trouble when it matches more than one filter condition (it'll be displayed more than once).
$(arr).each(function (i, v) {
// this section must be filter "pack's" but i can't writ correct query
li += '<li>' + jsn[key].name + '</li>';
});
Here is a working jsFiddle
I want to get the json data from a file which has a nested JSON objects, like this.
{
"userId": "1",
"data": {
"id": 1,
"name" : "Lorem Ipsum",
"value" : "Salut Dolor"
}
}
And once I get it I want to create a select object with the Id as the displayed text and append it to a div.
Once the select object is created, I also want to automatically open the select options when the page gets loaded.
Once a value is selected from there, I want to display the name that is present in the json for that id.
I'm able to fetch only the UserId from this code, how will i meet the requirements?
$.ajax({
url: 'obj.json',
dataType: 'JSON',
success: function (data) {
var items = [];
$.each(data, function (key, value) {
items.push('<option id="' + key + '">' + value + '</option>');
});
$('<select/>', {
class: 'intrest-list',
html: items.join('')
}).appendTo('body');
},
statusCode: {
404: function () {
alert("There was a problem");
}
}
});
what is this good for? do you want to fetch more then 1 user in the future?
you could so something like this:
//user.json
[{id:1,name:'xxxx'},...]
....
for(var i = 0;i<data.length;i++){
items.push('<option id="' + data[i].id + '">' + data[i].name+'</option>');
}
...
or in your case, you can access it directly with:
data.data.id
data.data.name
data.data.value
would get you the right values
Solved it myself. Although i came up with an alternative to display the list of select elements as:
<select name="" id="details" size="2"></select>
also created a container to post the values of the JSON object selected from the select box:
<div id="container"></div>
and the jQuery part where the magic happens goes like this:
$.getJSON('obj.json', function(obj) {
$.each(obj, function(key, value) {
$("#details").append('<option>'+ value.name +'</option>')
});
$( "select" ).change(function () {
var value = $( "select option:selected").val();
$.each(obj, function(key, val) {
if (val.name == value) {
$("#container").html(val.value);
}
});
});
});
This pretty much made the select box as a list of items and the value.name selected in it makes the value.value visible in the div container.
I want to implement the ability to dynamically add comboboxes and I have to use Telerik ComboBox for that. I put this logic into button click.
$('#add-presenter').click(function (e) {
e.preventDefault();
var combobox = '#(Html.Telerik().ComboBox()
.Name("Presenters[" + (Model.Count) + "]")
.BindTo(new SelectList(LeaderList, "ID", "Value"))
.ClientEvents(ev => ev.OnChange("onSelect"))
.DataBinding(bnd => bnd.Ajax().Select("_LoadJournalist", "MonitoringFRadio"))
.Filterable(filter => filter.FilterMode(AutoCompleteFilterMode.StartsWith))
.HtmlAttributes(new { style = "width:320px;vertical-align:middle;" }))';
combobox = combobox.split('Presenters[' + index + ']').join('Presenters[' + (index + 1) + ']');
index++;
$('#presenters-block').append(combobox);
}
This code renders in browser as this:
$('#add-presenter').click(function (e) {
e.preventDefault();
var combobox = '<div class="t-widget t-combobox t-header" style="width:320px;vertical-align:middle;"><div class="t-dropdown-wrap t-state-default"><input class="t-input" id="Presenters[0]-input" name="Presenters[0]-input" type="text" /><span class="t-select t-header"><span class="t-icon t-arrow-down">select</span></span></div><input id="Presenters[0]" name="Presenters[0]" style="display:none" type="text" /></div>';
combobox = combobox.split('Presenters[' + index + ']').join('Presenters[' + (index + 1) + ']');
index++;
$('#presenters-block').append(combobox);
combobox = $('#Presenters\\['+index+'\\]').data('tComboBox');
});
The problem is in data-binding. This code generates proper HTML, but newly added list doesn't "drop"
When I do combobox = $('#Presenters\\['+index+'\\]').data('tComboBox'); for newly added item I get undefined (it exists, but data isn't set), so combobox.dataBind(dataSource) approach doesn't work.
Ok, I tried, but failed to do this without postback. Here's rough solution to the problem: do ajax request and replace content with partial view:
The Partial view:
#model List<int>
#{
var LeaderList = ViewData["LeaderList"] as List<ListItem>;
}
<div id="presenters-ajax-wrapper">
<div id="presenters-block">
#(Html.Telerik().ComboBox()
.Name("Presenters[0]")
.BindTo(new SelectList(LeaderList, "ID", "Value"))
.ClientEvents(ev => ev.OnChange("onSelect"))
.DataBinding(bnd => bnd.Ajax().Select("_LoadJournalist", "MonitoringFRadio"))
.Filterable(filter => filter.FilterMode(AutoCompleteFilterMode.StartsWith))
.HtmlAttributes(new { style = "width:320px;vertical-align:middle;" }))
#for(int i=1; i<Model.Count; i++)
{
var item = LeaderList.FirstOrDefault(l => l.ID == Model[i]);
var value = item != null ? item.Value : "";
#(Html.Telerik().ComboBox()
.Name("Presenters[" + i + "]")
.Value(value)
.BindTo(new SelectList(LeaderList, "ID", "Value"))
.ClientEvents(ev => ev.OnChange("onSelect"))
.DataBinding(bnd => bnd.Ajax().Select("_LoadJournalist", "MonitoringFRadio"))
.Filterable(filter => filter.FilterMode(AutoCompleteFilterMode.StartsWith))
.HtmlAttributes(new { style = "width:320px;vertical-align:middle;" }))
}
</div>
<button id="add-presenter" class="t-button">+</button>
<script type="text/javascript">
var index = #(Model.Count == 0 ? 0 : Model.Count-1);
$('#add-presenter').click(function (e) {
e.preventDefault();
index++;
var msg = $('#monitForm').serialize();
$.ajax({
url: '#Url.Action("_GetPresenters","MonitoringFRadio")'+'?count='+(index+1),
data: msg,
type: 'POST',
success: function(data) {
$('#presenters-ajax-wrapper').html(data);
}
});
});
</script>
</div>
Action:
[HttpPost]
public virtual ActionResult _GetPresenters(EditableMonitoring model, int count)
{
//some logic here...
return PartialView("EditorTemplates/Presenters", model.Presenters);
}
Well, probably it would be better to create another partial view which would render a single combobox, instead of redrawing all of them...
I have an <OL> and a function that reads in json and loads in <li>'s. I then have another function that looks at another json and loads the final <li>. I want the first function to trigger first and then the second to append the final <li> after. However, 1 out of every 10 or so page loads the second function triggers first and the <li>s are out of order. BTW the use case is for dynamic breadcrumbs. I am using twitter bootstrap's breadcrumb class to style these elements.
First Trigger:
$.getJSON("/requirementdesc/{{ catalog }}/"+ c, function(d) {
$.each(d, function(k, v) {
$(".breadcrumb").append("<li><a href='/{{ catalog }}/"+ c +"'>"+ v.raw_requirement_desc +"</a></li>");
});
});
Second Trigger:
$.getJSON("/parentrequirement/{{ catalog }}/{{ block }}", function(data) {
$.each(data, function(key, value) {
$(".breadcrumb").append("<li class='active'>"+ value.raw_requirement_desc +"</li>");
});
});
I have tried using .promise(), but no luck.
Use jQuery's $.when(), which provides a way to execute callback functions based on one or more objects that represent asynchronous events. This code waits for both calls to complete, and then appends the lis to the ol in order.
var li_1,
li_2;
$.when(
$.getJSON("/requirementdesc/{{ catalog }}/" + c, function (d) {
$.each(d, function (k, v) {
li_1 += "<li><a href='/{{ catalog }}/" + c + "'>" +
v.raw_requirement_desc + "</a></li>";
})
}),
$.getJSON("/parentrequirement/{{ catalog }}/{{ block }}", function (data) {
$.each(data, function (key, value) {
li_2 += "<li class='active'>" + value.raw_requirement_desc + "</li>";
})
})
)
.then(function(){
if(typeof li_1 === "string" && typeof li_1 !== "undefined") {
$(".breadcrumb").append(li_1);
}
if(typeof li_2 === "string" && typeof li_2 !== "undefined") {
$(".breadcrumb").append(li_2);
}
});
Note: I didn't test this but it should theoretically work, given your code.
I have the following JSON:
var questions = {
section: {
"1": question: {
"1": {
"id" : "1a",
"title": "This is question1a"
},
"2": {
"id" : "1b",
"title": "This is question2a"
}
},
"2": question: {
"1": {
"id" : "2a",
"title": "This is question1a"
},
"2": {
"id" : "2b",
"title": "This is question2a"
}
}
}
};
NOTE: JSON changed based on the answers below to support the question better as the original JSON was badly formatted and how it works with the for loop below.
The full JSON will have 8 sections and each section will contain 15 questions.
The idea is that the JS code will read what section to pull out and then one by one pull out the questions from the list. On first load it will pull out the first question and then when the user clicks on of the buttons either option A or B it will then load in the next question until all questions have been pulled and then do a callback.
When the button in the appended list item is clicked it will then add it to the list below called responses with the answer the user gave as a span tag.
This is what I have so far:
function loadQuestion( $section ) {
$.getJSON('questions.json', function (data) {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item === $section) {
$('#questions').append('<li id="' + item.section.questions.question.id + '">' + item.section.questions.question.title + ' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>');
}
}
});
}
function addResponse( $id, $title, $response ) {
$('#responses').append('<li id="'+$id+'">'+$title+' <span>'+$response+'</span></li>');
}
$(document).ready(function() {
// should load the first question from the passed section
loadQuestion( $('.section').data('section') );
// add the response to the list and then load in the next question
$('button.btn').live('click', function() {
$id = $(this).parents('li').attr('id');
$title = $(this).parents('li').html();
$response = $(this).data('response');
addResponse( $id, $title, $response );
loadQuestion ( $('.section').data('section') );
});
});
and the HTML for the page (each page is separate HTML page):
<div class="section" data-section="1">
<ul id="questions"></ul>
<ul id="responses"></ul>
</div>
I've become stuck and confused by how to get only the first question from a section and then load in each question consecutively for that section until all have been called and then do a callback to show the section has been completed.
Thanks
Do not have multiple id's in html called "section."
Do not have multiple keys in your JSON on the same level called "section". Keys in JSON on the same level should be unique just as if you are thinking about a key-value hash system. Then you'll actually be able to find the keys. Duplicate JSON keys on the same level is not valid.
One solution can be section1, section2, etc. instead of just section. Don't rely on data-section attribute in your HTML - it's still not good if you have "section" as the duplicate html id's and as duplicate JSON keys.
If you have only one section id in HTML DOM, then in your JSON you must also have just one thing called "section" e.g.:
var whatever = {
"section" : {
"1": {
"question" : {
"1" : {
"id" : "1a",
"title" : "question1a"
},
"2" : {
"id" : "2a",
"title" : "question2a"
}
}
},
"2": {
"question" : {
"1" : {
"id" : "1a",
"title" : "aquestion1a"
},
"2" : {
"id" : "2a",
"title" : "aquestion2a"
}
}
}
}
}
console.log(whatever.section[1].question[1].title); //"question1a"
To get question, do something like this:
function loadQuestions(mySectionNum) {
$.getJSON('whatever.json', function(data){
var layeriwant = data.section[mySectionNum].question;
$.each(layeriwant, function(question, qMeta) {
var desired = '<div id="question-' +
qMeta.id +
'"' +
'>' +
'</div>';
$("#section").append(desired);
var quest = $("#question-" + qMeta.id);
quest.append('<div class="title">' + qMeta.title + '</div>');
//and so on for question content, answer choices, etc.
});
});
}
then something like this to actually get the questions:
function newQuestion(){
var myHTMLSecNum = $("#section").attr('data-section');
loadQuestions(myHTMLSecNum);
}
newQuestion();
//below is an example, to remove and then append new question:
$('#whatevernextbutton').on('click',function(){
var tmp = parseInt($("#section").attr('data-section'));
tmp++;
$("#section").attr('data-section', tmp);
$("#section").find('*').remove();
newQuestion();
});
Technically your getJSON function always retrieves the same data. Your code never compares the id given to the id you're extracting.
Your getJSON should look something like:
function loadQuestion( $section ) {
for (var i = 0; i < questions.section.length; i++) {
var item = questions.section[i];
if (item.id === $section) {
for (var j = 0; j < item.questions.length; j++) {
$('#questions').append('<li id="' +
item.questions[i].id + '">' +
item.questions[i].title +
' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>'
);
}
}
}
}
Modify your JSON to:
var questions = {
section: [{
id: 1,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a",
title: "This is question2a"
}]},{
id: 2,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a"
title: "This is question2a"
}]
}]
};
Edit: your first parameter of getJSON is the URL of the JSON returning service.
You don't need getJSON at all if your JSON is already defined on the client. I have modified the code above.