Onsen Cards not showing? - javascript

I'm trying to use JavaScript to place cards for however many ids there are in a given JSON input, and while the divisions and cards exist in HTML, they don't show in practice. Can anyone shed some light on this problem?
I'm working on a college project, and for that we need to create an app in Cordova. Our team uses Onsen UI as a framework.
EDIT: It seems as though the division "page__background page--material__background" is obstructing my cards. Basically, they're being rendered behind it. I tried z-index in CSS and that didn't do anything. Anyone know how to get these cards to draw on top.
<ons-page id="policies-page">
<style>
.intro {
text-align: center;
padding: 0 20px;
margin-top: 40px;
}
ons-card {
cursor: pointer;
color: #333;
}
.card__title,
.card--material__title {
font-size: 20px;
}
</style>
<script>
var jojo;
var insertnode1, insertnode2, insertnode3;
function cardGenerator() {
fetch('https://api.thesmokinggnu.net/api/policies')
.then(response => response.json())
.then(data=>{
console.log(data)
// Work with JSON data here
jojo = document.getElementById("policies-page");
for (policy of data.policies){
insertnode2 = document.createElement("DIV");
insertnode2.innerHTML = "<ons-card id='policycards' onclick='fn.pushPage({`id`: `policy_read.html`, `title`: `ID: "+policy.id+"`})'>"+policy.policyname+"</ons-card>"
jojo.appendChild(insertnode2);
}
})
}
cardGenerator();
//<ons-card onclick='fn.pushPage({`id`: `policy_read.html`, `title`: `ID: "+policy.id+"`})'>"+policy.policyname+"</ons-card>
</script>
</ons-page>
</template>```
In theory; this code, with the typical JSON input of 6 ids, should output 6 cards with the ID and other information. Instead, no cards. Not even an error.

Create div inside ons-page and add your cards inside this div:
<ons-page id="policies-page">
<div id="cards"></div>
<style>
...
</style>
<script>
var jojo;
var insertnode1, insertnode2, insertnode3;
function cardGenerator() {
fetch('https://api.thesmokinggnu.net/api/policies')
.then(response => response.json())
.then(data=>{
console.log(data)
// Work with JSON data here
jojo = document.getElementById("cards");
for (policy of data.policies){
insertnode2 = document.createElement("DIV");
insertnode2.innerHTML = "<ons-card ...</ons-card>"
jojo.appendChild(insertnode2)
}
})
}
cardGenerator();
</script>
</ons-page>
Here is a working snippet example:
var jojo;
var insertnode1, insertnode2, insertnode3;
function cardGenerator() {
let data = {policies:[
{id:1, policyname: "policyname1"},
{id:2, policyname: "policyname2"},
{id:3, policyname: "policyname3"}
]}
jojo = document.getElementById("cards");
for (policy of data.policies){
insertnode2 = document.createElement("DIV");
insertnode2.innerHTML = "<ons-card>" + policy.policyname + "</ons-card>"
jojo.appendChild(insertnode2);
}
}
cardGenerator();
.intro {
text-align: center;
padding: 0 20px;
margin-top: 40px;
}
ons-card {
cursor: pointer;
color: #333;
}
.card__title,
.card--material__title {
font-size: 20px;
}
<link href="https://unpkg.com/onsenui/css/onsenui.css" rel="stylesheet"/>
<link href="https://unpkg.com/onsenui/css/onsen-css-components.css" rel="stylesheet"/>
<script src="https://unpkg.com/onsenui/js/onsenui.js"></script>
<ons-page id="policies-page">
<div id='cards'></div>
</ons-page>
Why do we need to do so: when ons-page is compiled it has divs inside. One of them is div with page__content class and it seems like we can see only elements inside this div. When you append to ons-page you append outside of div.page__content. That is why we can't see appended elements.

Related

id values turns always same from foreach in mvc view page

I am using mvc .net core for a project and I have a view page. I need some id values from this page for using them inside partial view. Because I am using those id values for foreign key in another table to post. From main page these values posts in database correctly. I always post 5 values and always 5 id there in database I saw when I checked. But when I click the accordion this id always turns first id from these 5 values. if I posted as 6,7,8,9,10 it just turns me 6 and it doesn't matter if I clicked the last one in the page or first one. But context and title always correct when I check it from database and from page.
I tried a few jquery code but they didn't work correctly. I need the correct id values when I click other accordions.
I would be glad for any kind of help. Thanks a lot.
Here is my code:
#model IEnumerable<match>
#{
ViewData["Title"] = "Home Page";
}
<head>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<style>
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
</style>
</head>
<body>
<h4>Title List:</h4>
<table class="table table-hover">
#foreach (var item in Model)
{
<tr class="yzt">
<td class="xyz" id="item_title" >
<button class="accordion" id="title" >#Html.DisplayFor(modelItem => item.title)</button>
<div class="panel">
<p id="modelId" hidden>#Html.DisplayFor(modelItem=>item.Id)</p>
<p>#Html.DisplayFor(modelItem => item.context)</p>
#await Html.PartialAsync("Create", item.Exams#*, Exams*#)
</div>
</td>
</tr>
}
</table>
<script>
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function () {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
//document.querySelectorAll('.accordion').forEach(link => this.addEventListener('click', myFunction))
//function myFunction() {
// document.getElementById("matchId").value = document.getElementById("modelId").innerHTML;
// console.log("value is" + document.getElementById("matchId").value);
//}
document.querySelectorAll('.panel').forEach(link => this.addEventListener('click', myFunction))
function myFunction() {
document.getElementById("matchId").value = document.getElementById("modelId").innerHTML;
console.log("value is" + document.getElementById("matchId").value);
}
//document.querySelectorAll(".accordion")
//document.getElementById("match_title").value = document.getElementById("title").innerHTML;
</script>
</body>
I recommend you to write like this:
<div class="panel" id=#item.Id onclick="test(#item.Id)">
function test(val){
alert(val);
}
Your code will create multiple having id "title" and multiple having id "modelId", and this is also the reason why you always get the id from the first item, what you write document.getElementById("modelId").innerHTML will always get the first dom element which id = "modelId"

Using template strings to append HTML

New to es6, is there a way to append HTML using template literals `` in the DOM without overwriting what was currently posted?
I have a huge block of HTML that I need to post for a list that is being created. Where a user is able to post their input.
Every-time the task is submitted it overwrites the current submission. I need it to append underneath.
fiddle for demonstration purpose.
https://jsfiddle.net/uw1o5hyr/5/
<div class = main-content>
<form class ='new-items-create'>
<label>Name:</label><input placeholder=" A Name" id="name">
<button class = "subBtn">Submit</button>
</form>
</div>
<span class="new-name"></span>
JavaScript
form.addEventListener('submit',addItem);
function addItem(event){
event.preventDefault();
let htmlStuff =
`
<div class="main">
<div class="a name">
<span>${name.value}</span>
</div>
<div>
`
itemCreated.innerHTML = htmlStuff;
}
insertAdjacentHTML() adds htmlString in 4 positions see demo. Unlike .innerHTML it never rerenders and destroys the original HTML and references. The only thing .innerHTML does that insertAdjacentHTML() can't is to read HTML. Note: assignment by .innerHTML always destroys everything even when using += operator. See this post
const sec = document.querySelector('section');
sec.insertAdjacentHTML('beforebegin', `<div class='front-element'>Front of Element</div>`)
sec.insertAdjacentHTML('afterbegin', `<div class='before-content'>Before Content</div>`)
sec.insertAdjacentHTML('beforeend', `<div class='after-content'>After Content</div>`)
sec.insertAdjacentHTML('afterend', `<div class='behind-element'>Behind Element</div>`)
* {
outline: 1px solid #000;
}
section {
margin: 20px;
font-size: 1.5rem;
text-align: center;
}
div {
outline-width: 3px;
outline-style: dashed;
height: 50px;
font-size: 1rem;
text-align: center;
}
.front-element {
outline-color: gold;
}
.before-content {
outline-color: blue;
}
.after-content {
outline-color: green;
}
.behind-element {
outline-color: red;
}
<section>CONTENT OF SECTION</section>
You can just use += to append:
document.getElementById('div').innerHTML += 'World';
<div id="div">
Hello
</div>
Element.prototype.appendTemplate = function (html) {
this.insertAdjacentHTML('beforeend', html);
return this.lastChild;
};
If you create the element prototype as per above, you can get the element back as reference so you can continue modifying it:
for (var sectionData of data) {
var section = target.appendTemplate(`<div><h2>${sectionData.hdr}</h2></div>`);
for (var query of sectionData.qs) {
section.appendTemplate(`<div>${query.q}</div>`);
}
}
Depending on how much you're doing, maybe you'd be better off with a templating engine, but this could get you pretty far without the weight.

How can I use method on object which name I have as a string?

I'm coming back with another problem.
I have such code:
HTML
<button>first</button>
<button>second</button>
<div class="first"></div>
<div class="second"></div>
CSS
div{
margin-top: 10px;
width: 100px;
height: 100px;
border:1px solid black;
background-color: #ddd;
}
JS
const btns = document.querySelectorAll("button");
const first = document.querySelector(".first");
const second = document.querySelector(".second");
btns.forEach(btn => btn.addEventListener("click", function(){
this.classList.toggle("pressed");
let selection = this.textContent;
// selection.style.transform = "translate(100px)";
}))
https://codepen.io/ptr11dev/pen/oREymM
I'd like to create one function that'll be responsible for moving respective div to the right side by 100px - I stuck with such problem. Under "selection" I have respective name of div (stored under the same name), but simple code like
selection.style.transform = "translate(100px);"
doesn't work. I know that workaround like creating two functions and using
first.style.transform = "translate(100px);"
and
second.style.transform = "translate(100px);"
would work, but in my main code it's a bit more complicated.
I'll really appreciate any input from your side. Thanks
P.S. I'd like to use Vanilla JS.
You can find them by the class name, assuming that the button text and their class are the same.
const btns = document.querySelectorAll("button");
const first = document.querySelector(".first");
const second = document.querySelector(".second");
btns.forEach(btn => btn.addEventListener("click", function(){
this.classList.toggle("pressed");
let selection = this.textContent;
document.querySelector(`.${selection}`).style.transform = "translate(100px)";
}))
div{
margin-top: 10px;
width: 100px;
height: 100px;
border:1px solid black;
background-color: #ddd;
}
<button>first</button>
<button>second</button>
<div class="first"></div>
<div class="second"></div>
Your problem is textContext is just that TEXT not an object. This sets selection as the first element that matches the class name pulled as this.textContent;
let selection = document.getElementsByClassName(this.textContent)[0];
selection.style.transform = "translate(100px)";

Loading spinner VueJS

I have to make a loading animation when a client clicks the button search to popup a spinner animation, in order the client can't click multiple times on the search button. However, I don't know how to call this animation. I have made this until now:
table.vue:
<div id="overlay-back"></div>
<div id="overlay">
<div id="dvLoading">
<img id="loading-image" src="../assets/images/spinner.gif" alt="Loading..."/>
</div>
</div>
loadData(filter) {
var self = this;
const url = this.$session.get('apiUrl') + 'loadSystemList'
this.submit('post', url, filter);
}
main.css:
#overlay {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
z-index : 995;
display : none;
}
#overlay-back {
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
background : #000;
opacity : 0.6;
filter : alpha(opacity=60);
z-index : 990;
display : none;
}
#dvLoading {
padding: 20px;
background-color: #fff;
border-radius: 10px;
height: 150px;
width: 250px;
position: fixed;
z-index: 1000;
left: 50%;
top: 50%;
margin: -125px 0 0 -125px;
text-align: center;
display: none;
}
I need to call the animation when the button Search is clicked and invokes the function loadData. I would be happy if you help me guys :) I am kinda lost
Update1:
file.vue:
<template>
<div>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.1/css/all.css" integrity="sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ" crossorigin="anonymous">
<div id="dvLoading">
<i class="fa fa-spinner fa-spin fa-10x"></i>
</div>
<div class="toolbarStrip">
<br><h1 style="text-align: center; padding-bottom: 10px;">System table</h1>
<fieldset class="buttons">
<span class="logInBTN" v-on:click="loadData(filter)" id="loadData">Search</span>
</fieldset>
</div>
</div>
</template>
<script type="text/javascript">
import config from '../main.js'
var loadButton = document.getElementById("loadData");
export default {
data(){
return {
},
methods: {
stopShowingLoading(){
var element = document.getElementById("dvLoading");
element.classList.remove("showloading");
var button = document.getElementById("loadData");
button.classList.remove("showloading");
},
loadData(filter) {
var element = document.getElementById("dvLoading");
element.classList.add("showloading");
var button = document.getElementById("loadData");
button.classList.add("showloading");
var self = this;
const url = this.$session.get('apiUrl') + 'loadSystemList'
this.submit('post', url, filter);
window.setTimeout(function(){stopShowingLoading();},3000);
},
submit(requestType, url, submitData) {
this.$http[requestType](url, submitData)
.then(response => {
this.items = response.data;
})
.catch(error => {
console.log('error:' + error);
});
},
newData: function(){
config.router.push('/systemData')
}
}
}
</script>
first of all, whilst I have done things with vue.js in the past, I've forgotten much of that so there may be a better way within that framework than this, which is a vanilla JS approach really...
You don't seem to have a requirement to stop showing the loading animation. When I've done this sort of thing in the past, I've usually made use of callbacks to know when the loading operation is complete, and at that point 'turn off' the loading animation. I've included a function to hide the loading, but don't know where/if you'd want to call this.
This is untested, so apologies for typos or other minor errors...
css:
/*
Override the display:none on the #dvloading element if it has a class
of 'showloading
*/
#dvLoading.showloading{
display:block
}
JS:
function loadData(filter) {
/*
Add the 'showloading' class to the #dvLoading element.
this should make it appear due to the css change...
*/
var element = document.getElementById("dvLoading");
element.classList.add("showloading");
var self = this;
const url = this.$session.get('apiUrl') + 'loadSystemList'
this.submit('post', url, filter);
}
function stopShowingLoading(){
/*
When loading finishes, reverse the process
*/
var element = document.getElementById("dvLoading");
element.classList.remove("showloading");
}
edit: jsFiddle to show general approach
further edit: To stop showing animation only after data has loaded (I just used a timeout to simulate this in my example) then you need to simply stop it after the data has loaded, which would be something like this:
submit(requestType, url, submitData) {
this.$http[requestType](url, submitData)
.then(response => {
// We've received the data now, so set items and
//also hide the loading animation.
this.items = response.data;
this.stopShowingLoading();
})
...
and then remove the window.setTimeout() call altogether.

Jquery accordion type functionality only one item open at a time

I Have a custom designed grid:
http://jsfiddle.net/97n4K/
when you click a grid item the content div of that item slides open and when you click it again it closes. This works fine.
My problem is i only ever want one content area to open at a time much like a standard accordion.
So for instance i click 'content one' - it opens 'content area one' - now if i click 'content two' i want 'content area one' to close (slideUp) and 'content area two' to open (slideDown) at the same time - just like an accordion does.
Obviously my html is alot different from a standard accordion setup so im stuggling to figure it out how to do it with my limited Jquery knowledge.
Please see my Js Fiddle above - and heres the code if you prefer below:
Thanks
HTML
<div style="width: 100%; height: 68px;">
<div class="expBtn exBlue ex1"><h3>Content<br>one</h3></div>
<div class="expBtn exOlive ex2"><h3>Content<br>two</h3></div>
<div class="expBtn exOrange ex3"><h3>Content<br>three</h3></div>
</div>
<div class="expArea expArea1">
This is content one
</div>
<div class="expArea expArea2">
This is content two
</div>
<div class="expArea expArea3">
This is content three
</div>
CSS
.expBtn {
width: 190px;
height: 68px;
text-decoration: none;
background-color: #000;
float: left;
cursor: pointer;
}
.expBtn h3 {
font-size: 18px;
font-weight: bold;
color: #e8e7e4;
text-transform: none;
line-height: 1.2em;
letter-spacing: 0em;
padding-top: 13px;
padding-left: 13px;
padding-right: 13px;
padding-bottom: 0;
font-family: arial;
margin: 0;
}
.expArea {
display: none;
width: 570px;
background-color: #ccc;
height: 200px;
}
JS
$(".ex1").click(function () {
$(".expArea1").slideToggle(1000);
});
$(".ex2").click(function () {
$(".expArea2").slideToggle(1000);
});
$(".ex3").click(function () {
$(".expArea3").slideToggle(1000);
});
$(".exBlue").hover(function () {
$(this).css("background-color","#0092d2");
}, function() {
$(this).css("background-color","#000");
});
$(".exOlive").hover(function () {
$(this).css("background-color","#9bad2a");
}, function() {
$(this).css("background-color","#000");
});
$(".exOrange").hover(function () {
$(this).css("background-color","#ff8a0c");
}, function() {
$(this).css("background-color","#000");
});
Ok so i have created essentially what i want but i have a massive load of duplicate JS that i know could be simplified by any one with better knowledge of jquery / javascript than me. Please check out this new JS fiddle - any solution to get the JS down would be greatly appreiated!
Thanks
NEW JS FIDDLE
http://jsfiddle.net/97n4K/9/
If you wish to keep your same html structure you can use the following to get what you want;
JS FIDDLE DEMO
Switch your JS click handling to this;
$('.expBtn').on('click', function () {
var area = $(this).index() + 1;
var new_div = $('.expArea' + area);
// do nothing if it's already visible
if (!new_div.is(':visible'))
{
// slide up all first
$('.expArea').slideUp(300);
new_div.slideDown(1000);
}
});
You can easily add more html sections providing you follow the same numbering you've already done.
You can use slideUp or slideDown? Im not 100% sure as to what exactly you want to achieve but this fiddle should help you.
$(".ex1").click(function () {
$(".expArea1").slideToggle(1000);
$(".expArea2").slideUp(1000);
$(".expArea3").slideUp(1000);
});
$(".ex2").click(function () {
$(".expArea2").slideToggle(1000);
$(".expArea1").slideUp(1000);
$(".expArea3").slideUp(1000);
});
$(".ex3").click(function () {
$(".expArea3").slideToggle(1000);
$(".expArea2").slideUp(1000);
$(".expArea1").slideUp(1000);
});
http://jsfiddle.net/97n4K/5/
Basically you can use a plugin for this and it will help better
I have added some simple code so your code can work
<div style="width: 100%; height: 68px;">
<div class="expBtn exBlue ex1" data-accord = "expArea1"><h3>Broadcast + Arts + Media</h3></div>
<div class="expBtn exOlive ex2" data-accord = "expArea2"><h3>Business<br>Services</h3></div>
<div class="expBtn exOrange ex3" data-accord = "expArea3"><h3>Charity +<br>NFP</h3></div>
</div>
<div class="expArea expArea1">
expArea1 content
</div>
<div class="expArea expArea2">
expArea2 content
</div>
<div class="expArea expArea3">
expArea3 content
</div>
Please look at data-accord and it's content
Now for the JS
$('.expBtn').click(function(){
var current = $(this).data('accord');
$('.expArea').each(function(){
if($(this).not('.'+current).css('display') == "block")
{
$(this).slideToggle();
}
});
$('.'+current).slideToggle(1000);
});
$(".exBlue").hover(function () {
$(this).css("background-color","#0092d2");
}, function() {
$(this).css("background-color","#000");
});
$(".exOlive").hover(function () {
$(this).css("background-color","#9bad2a");
}, function() {
$(this).css("background-color","#000");
});
$(".exOrange").hover(function () {
$(this).css("background-color","#ff8a0c");
}, function() {
$(this).css("background-color","#000");
});
You can see it working
http://jsfiddle.net/97n4K/6/
I hope this can help

Categories