I'm creating my own auto suggest with my input on HTML with pure JavaScript Standard DOM. I'm trying to code my own without using JavaScript Framework with external json file. This is my code so far:
<input type="text" class="input_data" id="Music_Genre" onKeyUp="suggestMusicGenre(this.value, event)" />
<div id="musicgenre_suggest"></div>
function suggestMusicGenre(key, e) {
var targetelem = document.getElementById('musicgenre_suggest');
var temp_array = [];
// basic style for div element
$("#musicgenre_suggest").css({
'position':'absolute',
'background-color':'#fff',
'width': $("#Music_Genre").css('width'),
'cursor':'pointer',
'border':'1px solid #a4a4a4'
});
$.getJSON('json/musicgenre.json', function(data) {
$.each(data, function(index, value) {
var str = value.toString().toLowerCase();
var findstr = str.match(key.toString().toLowerCase());
var boolIfInsert = (findstr != null) ? temp_array.push(value) : false;
});
var prent = document.createElement('ul');
prent.style.listStyleType = "none";
for(var o in temp_array) {
var chld = document.createElement('li');
var txtchld = document.createTextNode(temp_array[o]);
chld.appendChild(txtchld);
prent.appendChild(chld);
}
targetelem.innerHTML = '';
targetelem.appendChild(prent);
});
}
and this is my json file content:
{
"AL" : "Alternative Music",
"BL" : "Blues",
"CM" : "Classical Music",
"CoM" : "Country Music",
"DM" : "Dance Music",
"EL" : "Easy Listening",
"EM" : "Electronic Music"
}
It works fine but I need to add more functionality in it like Facebook does which automatically making some suggested candidate string makes differ its color among to user already typed like example below:
Is is possible with pure standard JavaScript? or should I use JavaScript Framework then?
You can use jQuery UI auto-complete for this. http://jqueryui.com/autocomplete/
CSS
First, let's decide how out list item will look (this won't be the part of the final code, just to get the idea):
<div class="list_item_container">
<div class="image"><img src="hanks.png"></div>
<div class="label">Tom hanks</div>
<div class="description">Actor</div>
</div>
And the formatting (this should go in your stylesheets):
DIV.list_item_container {
height: 90px;
padding: 5px;
}
DIV.image {
width: 90px;
height: 80px;
float: left;
}
DIV.description {
font-style: italic;
font-size: 0.8em;
color: gray;
}
Javascript
Now, creating the autocomplete and overriding _renderItem() method:
$(function() {
$("#my_ac").autocomplete({
source: [
{
value: "Tom Hanks",
label: "Tom Hanks",
description: "Actor",
image: "hanks.png"
},
{
value: "Termionator 2",
label: "Termionator 2",
description: "Movie",
image: "terminator.png"
}
],
minLength: 1
}).data( "autocomplete" )._renderItem = function( ul, item ) {
var inner_html = '<a><div class="list_item_container"><div class="image"><img src="' + item.image + '"></div><div class="label">' + item.label + '</div><div class="description">' + item.description + '</div></div></a>';
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append(inner_html)
.appendTo( ul );
};
});
Please note, that inner is inside tags. This might not be the proper HTML, but it's the only way to make the whole item clickable.
HTML
Now just create an input with id my_ac and you are done:
<input type="text" id="my_ac" size="40" />
Reference here.
Related
I am getting JSON data (businesses) from the yelp API. I loop through the data to display the businesses, and want to display more information about the business when clicked on in another div. So far I have:
function display_results(businesses) {
var options = '';
for (var i = 0; i < businesses.length; i++) {
options += '<div class="optbtn" value="' + i + '">' + businesses[i].rating.toFixed(1) + "/5\u2606 " + businesses[i].name + '</div>';
}
$('#businesses').html(options);
$('.optbtn').click(function () {
// index problems
var index = $(this).val();
console.log("index: " + index);
var details = businesses[index];
var info = '';
for (key in details) {
info += key + ': ' + details[key] + '<br>';
}
$('#info').html(info);
});
}
$(function () {
$("#search_bar").autocomplete({
source: "/autocomplete",
minLength: 3,
select: function (event, ui) {
$.ajax({
url: "/business_search",
type: "GET",
data: {
term: ui.item.value
},
success: function (result) {
display_results(JSON.parse(result).businesses);
}
});
}
});
});
<div class="ui-widget">
<label for="search_bar">Business Search: </label>
<input id="search_bar" style="width: 400px;">
</div>
<div class="ui-widget">
Businesses:
<div id="businesses" style="height: 400px; width: 600px; overflow: auto; white-space: pre;"
class="ui-widget-content" />
</div>
<div class="ui-widget">
Info:
<div id="info" style="height: 400px; width: 600px; overflow: auto; white-space: pre;"
class="ui-widget-content" />
</div>
My plan was to set an index value for each div containing a business and then upon click use that value to get the rest of the information to display. My problem is that I seem to not be able to actually get the index value using var index = $(this).val();. I am new to all of this and would love some guidance on where I went wrong!
The main issue in your code is because valid HTML div elements should not have a value attribute to be read through jQuery's val() method. The easy fix for this would be to use data attribute to store the index or id of the related array entity within the HTML.
Also note that there's some other optimisations you can make to the logic to improve it:
Use Array.map() and string interpolation to build the HTML more succinctly
Use a single delegated event handler for all dynamic content
Use Object.entries() to retrieve an array-like object containing the key/value pairs within a given object.
Put CSS rules in an external CSS stylesheet, not inline in HTML
With that said, this should work for you:
jQuery($ => {
let $businesses = $('#businesses');
// handle click on the business rating
$businesses.on('click', '.optbtn', e => {
let index = $(e.currentTarget).data('index');
let business = $businesses.data('response')[index];
$('#info').html(Object.entries(business).map(([k, v]) => `<p>${k}: ${v}</p>`));
});
// update the DOM based on the AJAX response:
let display_results = businesses => $businesses.html(businesses.map((b, i) => `<div class="optbtn" data-index="${i}">${b.rating.toFixed(1)}/5\u2606 ${b.name}</div>`))
// make your Autocomplete/AJAX call here.
// mock AJAX response handler:
let ajaxResponse = [{ rating: 1.11, name: 'Foo', address: '123 Any Street' },{ rating: 2.22, name: 'Bar', address: '456 Any Town' },{ rating: 4.44, name: 'Fizz', address: '789 Any City' },{ rating: 5.00, name: 'Buzz', address: '123 Any Avenue' }];
display_results(ajaxResponse); // build the UI from the dataset
$businesses.data('response', ajaxResponse); // store the response for later use
});
#search_bar {
width: 400px;
}
.ui-widget-content {
width: 600px;
overflow: auto;
margin-bottom: 10px;
}
.ui-widget-content p {
margin: 0 0 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="ui-widget">
<label for="search_bar">Business Search:</label>
<input id="search_bar" />
</div>
<div class="ui-widget">
Businesses:
<div id="businesses" class="ui-widget-content"></div>
</div>
<div class="ui-widget">
Info:
<div id="info" class="ui-widget-content"></div>
</div>
I am trying to add a class when looping through an array, here is my current code:
var users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
];
var div = "<div>";
for (var i = 0; i < users.length; i++) {
div += "<p>" + users[i].name + "</p>";
div += "<p>" + users[i].id + "</p>";
div += "<p>" + users[i].number + "</p>";
}
div += "</div>";
document.getElementById("usersList").innerHTML = div;
<div class="contact-container">
<div class="navbar">
<ul>
<li>
<img src="https://img.icons8.com/ios-filled/50/000000/contact-card.png" />
</li>
<li>
View
</li>
<li>
Add
</li>
...
</ul>
</div>
<div class="users" id="usersList">
</div>
Is there any way I can add a class when looping?
Why don't you put a class right there while looping?
like this
for (var i = 0; i < users.length; i++) {
div += "<p class='myclass'>" + users[i].name + "</p>";
div += "<p class='myclass'>" + users[i].id + "</p>";
div += "<p class='myclass'>" + users[i].number + "</p>";
}
Just add it into your HTML
for (var i = 0; i < users.length; i++) {
div += "<p class='user-name'>" + users[i].name + "</p>";
div += "<p class='user-id'>" + users[i].id + "</p>";
div += "<p class='user-number'>" + users[i].number + "</p>";
}
var users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
];
var div = "<div>";
for (var i = 0; i < users.length; i++) {
div += "<p class='user-name'>" + users[i].name + "</p>";
div += "<p class='user-id'>" + users[i].id + "</p>";
div += "<p class='user-number'>" + users[i].number + "</p>";
}
div += "</div>";
document.getElementById("usersList").innerHTML = div;
.user-name {
color: red;
}
.user-id {
color: blue;
}
.user-number {
color: green;
}
<div class="contact-container">
<div class="navbar">
<ul>
<li>
<img src="https://img.icons8.com/ios-filled/50/000000/contact-card.png" />
</li>
<li>
View
</li>
<li>
Add
</li>
...
</ul>
</div>
<div class="users" id="usersList">
</div>
You could try creating your elements like this:
let div = document.createElement("div");
let p = document.createElement("p");
then add the class name:
p.className = "css class";
then add the parts to their parents:
div.appendChild(p);
document.getElementById("usersList").appendChild(div);
This is cleaner and more efficient than adding elements with innerHTML
While you've already accepted an answer, I thought this might be an interesting opportunity to try to learn – for my own benefit, but hopefully to contribute an answer – about using custom elements.
So, with that in mind see the code below with its explanatory comments (though this remains something of a black-magic to me, hence my interest in working on it to formulate an answer):
// defining the custom-element, naming it 'user-card' which
// will lead to the element being a <user-card> element in the DOM:
customElements.define('user-card',
class extends HTMLElement {
constructor() {
super();
// we get the <template> element via its id (other
// selection methods are available, of course):
let template = document.getElementById('user-card');
// and retrieve its content:
let templateContent = template.content;
// here we assign its shadow root as 'open', which
// allows us - and JavaScript - to modify it:
const shadowRoot = this.attachShadow({
mode: 'open'
})
// and here we append the content of the <template>,
// including its child nodes (the 'true' argument
// to cloneNode()):
.appendChild(templateContent.cloneNode(true));
}
}
);
// your data:
let users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
],
userDiv = document.querySelector('#usersList');
// here we use Array.prototype.forEach() to iterate over the
// data, along with an anonymous Arrow function to pass the
// current user Object into the body of the function:
users.forEach(
(user) => {
// we create a new <user-card> element:
let card = document.createElement('user-card'),
// we create a new <li> element:
li = document.createElement('li'),
// we create a document fragment to contain the
// HTML we're going to create to hopefully minimise
// repaints:
fragment = document.createDocumentFragment();
// we then use Object.prototype.keys() to iterate over the
// array of Object keys returned (in order to access the
// contents of the user Object), and pass that key into
// the body of the function:
Object.keys(user).forEach(
(key) => {
// we create a clone of the <li> element:
let clone = li.cloneNode();
// we apply the class-name of the current key, so
// each element gets a class of 'name', 'id' or 'number',
// obviously other classes could be used but these made
// the most sense given the context:
clone.classList.add(key);
// because the <style> of the <user-card> element's template
// doesn't (seem to) apply to content added later, we use
// CSSStlyleDeclaration.setProperty() to set the relevant
// CSS properties of the cloned <li> element; here we
// define the 'grid-area' property to properly place the
// current element into the appropriate grid-area (defined
// in the <template>):
clone.style.setProperty('grid-area', key);
// we add the property-value of the current Object key:
clone.textContent = user[key];
// and append the clone to the fragment, using
// Element.append():
fragment.append(clone);
})
// once all the data is within the document fragment, we
// append that fragment to the <user-card> element:
card.append(fragment);
// and then append that <user-card> to the relevant ancestor
// <div> in the document:
userDiv.append(card);
});
/* a very basic reset, to minimise cross-browser differences and
and reset elements to their basic 'zero-style' state: */
*,
::before,
::after {
box-sizing: border-box;
font-size: 1rem;
font-family: Calibri, Helvetica, Ubuntu, Arial, sans-serif;
line-height: 1.4;
margin: 0;
padding: 0;
}
.users {
/* specifying display: grid, since it's a typical (and
relatively aesthetic) convention for 'cards': */
display: grid;
gap: 0.5em;
/* allows the grid to adjust its layout to best fit the
content within the constraints of the device: */
grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
margin: 1em auto;
max-width: 90vw;
}
<!-- the template element that contains the structure to be re-used, with an id
attribute for easy access via JavaScript, though other means of selection
are possible -->
<template id="user-card">
<!-- because the defined style of the light DOM (or COM) doesn't penetrate
into the shadow root we declare relevant CSS here, though there are
concerns about this too; from experimentation the CSS declared here
will target elements present in the <template> but not content added
later, via JavaScript: -->
<style>
ol {
border: 1px solid #ccc;
list-style-type: none;
display: grid;
gap: 0.5em;
grid-template-areas:
"id name name"
"number number number";
padding: 0.25em;
margin: 0;
}
</style>
<!-- I've chosen to use an <ol> since the data seems to be
ordered/structured: -->
<ol>
<!-- we use a <slot> element to contain the data we'll be appending
(later) via JavaScript: -->
<slot></slot>
</ol>
</template>
<!-- for reasons of brevity I removed the extraneous content and retained
only the minimal content relevant to the demo, which is why we have
only the elements below: -->
<div class="contact-container">
<div class="users" id="usersList"></div>
</div>
JS Fiddle demo.
References:
HTML:
<slot>.
<template>.
JavaScript:
Arrow functions.
Array.prototype.forEach().
CSSStyleDeclaration.setProperty().
document.createElement().
document.createDocumentFragment().
document.querySelector().
document.querySelectorAll().
Element.append().
Element.classList API.
Element.slot.
HTMLSlotElement.
HTMLTemplateElement.
Node.cloneNode().
Object.prototype.keys().
Bibliography:
How to pass option tags to a custom element as distributed nodes (aka <slot></slot>).
"Using Templates and Slots," MDN.
"Web Components Are Easier Than You Think," CSS-Tricks.
I have an array of objects like this
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
And then I have several divs' with data attribute data-id like this
<div id="TLF" class="c2">
<div id="ttimgs" class="mygalleryx lidf2" data-id="4891"> </div>
</div>
<div id="TLF" class="c2">
<div id="ttimgs" class="mygalleryx lidf2" data-id="4892"> </div>
</div>
Now what I am trying to achieve is to filter the array and the resulting array get the image data source from picture: apply to the image and then append the image to the right div with an identical userpostid in relation to the div data-id attr. eg userpostid=4891 append to dive with data-id = 4891.
So far I have tried the code below but I have problems with it creating images in divs' that don't have identical data-id 's
function checkpics(e) {
var x = parseInt(e);
var appendTLpic = TLPics.filter(element => element.userpostid === x);
$(".lidf2").each(function() {
var thisid = $(this).data('id')
$(TLPics).each(function() {
if (thisid == this.userpostid) {
$('[data-id="' + thisid + '"]').append('<a><img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="' + this.Picture + '" style=" display:inline-block"/></a>');
}
});
});
appendTLpic = [];
}
The first issue you have here is that you're duplicating both the #TLF and #ttimgs id attributes when they must be unique. Change them to classes.
Then you can loop through each .ttimgs element and find() the related object in the array by matching the data-id attribute to the userpostid property, before appending the new img. Try this:
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
$('.ttimgs').each(function() {
var src = TLPics.find(x => x.userpostid === $(this).data('id')).Picture;
$(this).append(`<img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="${src}" />`);
});
.userpictz {
display: inline-block;
/* just for this demo... */
border: 1px solid #C00;
width: 30px;
height: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4891"></div>
</div>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4892"></div>
</div>
After a lot of trial and error this is the code I came up with and it achieved my desired results from my question. this may not be the cleanest of code
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
var x;
var appendTLpic = [];
$(".mygalleryx").each(function () {
x = $(this).data('id')
appendTLpic = TLPics.filter(element => element.userpostid === x);
$(appendTLpic).each(function () {
var src = this.Picture
$(`.lidf2[data-id=${x}]`).append(`<img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="${src}" />`);
});
});
.userpictz {
display: inline-block;
/* just for this demo... */
border: 1px solid #C00;
width: 30px;
height: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4891"></div>
</div>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4892"></div>
</div>
When dealing with asp.net web-forms I would have simply solved this with a nested repeater where i get my images from a data-source controlled by the main repeater's hiddenfeild value. Now because my new application demands I have to use Ajax hense this complication.
So I create for each loop for my div with class .mygalleryx then retrieve each divs data-id. now I filter my array TLPics using my data-id variable x. I then nest a for each function for my new filtered array which I retrieve the picture. Now within my new filtered array each function I append my image to the matching div dat-id using my initial variable x and I am done. I am still learning I do wish to be corrected. But this answer has resolved my issue.
I want to display only parts of a .json that I scraped with scrapy.
the scrapy output looks something like this and has about 500 entries:
data.json
[
{
"Content":["<h2>Heading of Paragraph1</h2><p>the actual pargraph1</p>"],
"Titel": ["Heading of Paragraph1"]
}
,
{
"Content": ["<h2>Heading of Paragraph2</h2><p>the actual pargraph2</p>"],
"Titel": ["Heading of Paragraph2"]
}
,
{
"Content": ["<h2>Heading of Paragraph3</h2><p>the actual pargraph3</p>"],
"Titel": ["Heading of Paragraph3"]
}
]
What I want to do is to generate a list of All the "Titel" elements for the user to choose from. Then the website should display the chosen paragraphs.
I figured out that some javascript are probably the way to go. I plan to use chosen later to make the UI usable.
So far I came up with this html
index.html
<body>
<form action="/returnselected_paragraphs.js">
<select name="pargraphs" multiple>
<option value="Heading of Pargraph1">Heading of Paragraph1</option>
<option value="Heading of Pargraph2">Heading of Paragraph2</option>
<option value="Heading of Pargraph3">Heading of Paragraph3</option>
<!-- this should be genereated by javascript with data from the json --!>
<input type="submit">
</form>
<h1>output</h1>
<h2>Heading of Paragraph1</h2><p>the actual pargraph1</p>
<h2>Heading of Paragraph2</h2><p>the actual pargraph2</p>
<!-- this should be genereated by javascript with data from json--!>
My problem is the javascript.
I found this code on jsfiddle which seems similar to what I want, but the data is formated differently. I don't know how to adapt it to my data.
I put my idea here: https://jsfiddle.net/jtxzerpu/
Thank you all for your time, I hope I did stick to all the rules.
Try this
Iterate the array and create select
Bind change event on select on which content should be rendered.
Demo
var arr = [{
"Content": ["<h2>Heading of Paragraph1</h2><p>the actual pargraph1</p>"],
"Titel": ["Heading of Paragraph1"]
},
{
"Content": ["<h2>Heading of Paragraph2</h2><p>the actual pargraph2</p>"],
"Titel": ["Heading of Paragraph2"]
}, {
"Content": ["<h2>Heading of Paragraph3</h2><p>the actual pargraph3</p>"],
"Titel": ["Heading of Paragraph3"]
}
];
//prepare the options first
var options = arr.map( function( item ){
return "<option value='" + item.Titel[0] + "'>"+ item.Titel[0] + "</option>"
} ).join( "" );
//set all the options to select and then bind change event
$( "select" ).html( options ).change( function(){
$( "#paraContent" ).html( "" );
var val = $(this).val();
$( "#paraContent" ).html( val.map( function( title ){
return arr.find( (s) => s.Titel[0] == title ).Content[0];
}).join( "</br>" ) )
//console.log(val);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="/returnselected_paragraphs.js">
<select name="pargraphs" multiple>
</select>
<p id="paraContent">
</p>
<input type="submit">
</form>
You can build the options list easily:
const options = json_data.reduce(
function (fragment, item)
{
const option = document.createElement("option");
option.value = item.Titel[0];
option.textContent = option.value;
fragment.appendChild(option);
return fragment;
},
document.createDocumentFragment()
);
Then append the options to your select (the document fragment will "merge" with the select and disappear, don't worry).
From your reference on jsfiddle, you can modify that to the code below:
var data = [
{
"Content":["<h2>Heading of Paragraph1</h2><p>the actual pargraph1</p>"],
"Titel": ["Heading of Paragraph1"]
}
,
{
"Content": ["<h2>Heading of Paragraph2</h2><p>the actual pargraph2</p>"],
"Titel": ["Heading of Paragraph2"]
}
,
{
"Content": ["<h2>Heading of Paragraph3</h2><p>the actual
pargraph3</p>"],
"Titel": ["Heading of Paragraph3"]
}
]
$.each(data, function () {
var $option = $('<option/>').text(this.Titel[0]).val(this.Titel[0]);
$option.data("content",this.Content[0])
$('#selectCompany').append($option);
});
Here is the link to your modified code in action:
https://jsfiddle.net/azqxhjgx/
You can use click event on option to display the content of the object where you want, something like this:
$("#selected > option").click(function(){
// do whatever with $this.data("content")
})
I have an array of content that when simplified looks like this:
[
{ content_type: 1, content_body: "some text" },
{ content_type: 1, content_body: "some text" },
{ content_type: 2, content_body: "media link" },
{ content_type: 1, content_body: "some text" }
]
I now need to map through this array and have a switch statement checking content_type and rendering HTML based on it, so something like (note below syntax uses jsx, so it might look different from vanila JavaScript, but it is pretty self explanatory).
switch(item.content_type) {
case 1:
render (
<div class="text_content">
<p>{item.content_body}</p>
</div>
)
case 2:
render (
<div class="text_media">
<div>{item.content_body}</div>
</div>
)
}
Now the issue, If same content type follows one after another in the array (so first 2 entries with content_type 1 for example), I want their content_bodies to be rendered inside one div, so
<div class="text_content">
<p>{item.content_body}</p>
<p>{item.content_body}</p>
</div>
and then continue on if next content_type is different. (This can be repeated several times in the app, also this is only repeated for content_type 1).
What would be an approach for this? Bear in mind I can't manipulate array to do things like nest those contents inside an object.
If I understood your approach correctly then this should work just fine.
http://codepen.io/anon/pen/zrMEjz - working example
Code included below. Logic is that on each iteration it will check if an element exists then new element is inserted inside, if not, create that element and add element inside. (Note: jQuery included as a library, you can get away with using base JS but I wanted to show you the idea with slightly less code)
// sample array
var arr = [
{content_type: 1, content_body: "some text"},
{content_type: 1, content_body: "some text"},
{content_type: 2, content_body: "media link"},
{content_type: 1, content_body: "some text"}
];
for(var i = 0; i < arr.length; i++) {
var currentElement = arr[i]; console.log(currentElement.content_body);
switch(currentElement.content_type) {
case 1:
var el = jQuery('.text_content');
if(el.length) {
el.append('<p>' + currentElement.content_body + '</p>');
} else {
var el = jQuery('<div class="text_content"></div>')
el.append('<p>' + currentElement.content_body + '</p>');
jQuery('body').append(el);
}
break;
case 2:
var el = jQuery('.text_media');
if(el.length) {
el.append('<div>' + currentElement.content_body + '</div>');
} else {
var el = jQuery('<div class="text_media"></div>');
el.append('<p>' + currentElement.content_body + '</p>');
jQuery('body').append(el);
}
break;
}
}
.text_content {
border: 1px solid black;
}
.text_content p {
border: 1px solid yellowgreen;
}
.text_media {
border: 1px solid blue;
}
<html>
<body>
</body>
</html>
I hope this helps, let me know if it requires tweaking. Cheers.