modify handlebars template with javascript/jquery - javascript

I have a handlebars template such as this
<script type="text/html" id="some-id">
<div class="some-class-1" {{#if some_condition}}style="color:blue;"{{/if}}>
</div>
<div class="some-class-2">
<div class="some-nested-class-1">
</div>
</div>
<div class="some-class-3">
</div>
</script>
I want to modify this template for example add another div after div.some-nested-class-1
I used the following code, to parse the template to dom
jQuery(function ($) {
var t = $("#some-id");
var d = $("<div>").html(t.html());
console.log(d.html());
});
but it changes {{#if}} as follows :
<div class="some-class-1" {{#if="" some_condition}}style="color:blue;" {{="" if}}="">
</div>
<div class="some-class-2">
<div class="some-nested-class-1">
</div>
</div>
<div class="some-class-3">
</div>
Using Chrome and jsfiddle here https://jsfiddle.net/wv7hzx5a/
How can I achieve this without affecting the template?
Many thanks
PS: the template is being compiled in a separate script which I do not have access to change. I want to modify the template so that when the other script compiles it, the new elements will be included.

I don"t understand what you're trying to to and what you mean by parse the template to DOM. If you want to process the template and replace the handlebar code to have html, then use handlebar to do it and not jQuery. Only handlebar can interpret and translate the handlebar instructions to have the result. Then once that you have your result you can display it with jQuery if you want. Here is one example :
var context = {
"mydata": [
{
"character-id": "Luke1",
"firstname": "Luke",
"name": "Skywalker",
"age": "20",
"rebel": true
},
{
"character-id": "Leia1",
"firstname": "Leia",
"name": "Organa",
"age": "20",
"rebel": true
},
{
"character-id": "Vader1",
"firstname": "Darth",
"name": "Vader",
"age": "45",
"rebel": false
}
]
}
// Here you process the template and put it in the DOM
var template = $('#handlebars-demo').html();
var templateScript = Handlebars.compile(template);
var html = templateScript(context);
$("#placeholder").append(html);
// Once you have inserted your code in the DOM you can now use jQuery to modify it
// For example I put a star after Leia's section
$("#Leia1").html($("#Leia1").html()+"*")
</script>
.some-class-1 {
padding: 10;
min-width: 10px;
min-height: 20px;
border: solid blue 1px;
}
.some-class-2 {
padding: 10;
min-width: 10px;
min-height: 20px;
border: solid black 1px;
}
.some-class-3 {
padding: 10;
min-width: 10px;
min-height: 20px;
border: solid green 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js"></script>
<script type="text/html" id="handlebars-demo">
{{#each mydata}}
<div id="{{character-id}}">
<div class="some-class-1" {{#if rebel}}style="color:blue;"{{/if}}>
{{firstname}}
</div>
<div class="some-class-2" {{#if rebel}}style="color:blue;"{{/if}}>
{{name}}
</div>
<div class="some-class-3">
<div class="some-nested-class-1">
{{age}}
</div>
</div>
</div>
<br/>
{{/each}}
</script>
<div id="placeholder"></div>

Related

Vue with Muuri - how to use?

I'm very new to Vue and my web dev skills are very limited, so sorry if this is a basic questions.
I just wanted to explore how I could create a draggable grid interface in the browser and found the Muuri package.
Now just following the example code in plain JavaScript/HTML the demo works as expected.
Now I try it with Vue, I get an error saying -
"TypeError: Cannot read property 'getRootNode' of null"
Here is my Vue component that should use Muuri.
<template>
<div class="grid">
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
This can be anything.
<!-- Safe zone ends -->
</div>
</div>
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
<div class="my-custom-content">
Yippee!
</div>
<!-- Safe zone ends -->
</div>
</div>
</div>
</template>
<script>
import 'web-animations-js';
import Muuri from 'muuri';
export default {
name: 'Grid',
created() {
var grid = new Muuri('.grid', {dragEnabled:true});
console.log(grid.toString());
}
}
</script>
<style scoped>
.grid {
position: relative;
}
.item {
display: block;
position: absolute;
width: 100px;
height: 100px;
margin: 5px;
z-index: 1;
background: #000;
color: #fff;
}
.item.muuri-item-dragging {
z-index: 3;
}
.item.muuri-item-releasing {
z-index: 2;
}
.item.muuri-item-hidden {
z-index: 0;
}
.item-content {
position: relative;
width: 100%;
height: 100%;
}
</style>
Any help or advice much appreciated!
Your problem is likely that the DOM hasn't loaded when the created event hook gets executed. You could try using mounted instead. I've included a snippet.
new Vue({
el: "#app",
mounted() {
var grid = new Muuri('.grid', {dragEnabled:true});
alert(grid.toString());
}
});
<script src="https://unpkg.com/web-animations-js#2.3.2/web-animations.min.js"></script>
<script src="https://unpkg.com/muuri#0.8.0/dist/muuri.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" class="grid">
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
This can be anything.
<!-- Safe zone ends -->
</div>
</div>
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
<div class="my-custom-content">
Yippee!
</div>
<!-- Safe zone ends -->
</div>
</div>
</div>

Modifying JS pager - how to substitute html elements using JQuery

Here is the initial code:
<div class="fs-table-table">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div id="fs-table-content">
</div>
</div>
Now the pager file calls:
$('#' + options.contentHolder).html(template(pager, options.template, options.currentData, options.startPage, options.perPage, options.alwaysShowPager, options.informationToShow, options.errorTemplate));
where contentHolder is 'fs-table-content', and it points to a template:
<script type="text/template" id="weeklyLessonTemplate">
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
##courseName##
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="##lessons##" />
<label for="##lessons##">##lessons##
</label>
</div>
</div>
</script>
and it yields:
<div class="fs-table-table">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
Art/Music/Social Media
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="What is art?">
<label for="What is art?">What is art?
</label>
</div>
</div>
</div>
So you see, calling the function "template" simply returns html code. Now, when I click on the next page number, I expect the html to change but it doesn't change, it stays the same because
<div id="fs-table-content">
</div>
has been replaced. How do I inject fs-table-content back into the code. It should be put in the page onclick code:
$('#' + pager).on('click', '.page, .last-page, .first-page, .next-pages, .prev-pages', function(e) {
var newPage = parseInt($(this).data('value'));
var perPage = parseInt($('#' + pager + ' .perPage').val());
$('#' + pager + ' .page.current').removeClass('current');
$('#' + pager + ' .page[data-value="' + newPage + '"]').addClass('current');
showProperPaging(pager, newPage, options.totalPages, options.pagesToShow);
$('#' + options.contentHolder).html(template(pager, options.template, options.currentData, newPage, perPage, options.alwaysShowPager, options.informationToShow, options.errorTemplate));
options.currentPage = newPage;
$('#' + pager).trigger("pagingChange");
});
I noticed that in the demo for the pager, they use the following line to change the html:
var showing = $('#' + templateToShow).html().format(data);
html += showing;
But my data is structured differently, I don't think I can use .format
The way this script has been designed is that you need to provide two separate divs (not nested within one another). One for your content and one of its content (where it places pagination, search .. etc).
So you can change your code to this for it work:
!function(a){function e(e,t,r,n,o,s,g){var p="",l=Math.ceil(t/r);p+='<div class="showing"></div>',p+='<div class="pager"><span class="first-page btn" data-value="1">First</span><span class="prev-page btn">Previous</span><span class="prev-pages btn" data-value="1">...</span><span class="page btn current" data-value="1">1</span>';for(var i=1;i<l;i++)p+='<span class="page btn" data-value="'+(i+1)+'">'+(i+1)+"</span>";p+='\t<span class="next-pages btn" data-value="6">...</span><span class="next-page btn">Next</span><span class="last-page btn" data-value="'+l+'">Last</span></div>',p+='<div class="options" style="text-align: center; margin-bottom: 10px;"><span>Show </span><select class="perPage">';for(i=0;i<n.length;i++)n[i]==r?p+='<option selected="selected">'+n[i]+"</option>":p+="<option>"+n[i]+"</option>";p+="\t</select><span> per page</span></div>",s&&(p+='<div class="searchBox"><input type="text" class="search" placeholder="Search" value="'+g+'" /></div>'),a("#"+e).html(p)}function t(e,t,r,n){1==t?a("#"+e).find(".prev-page").hide():a("#"+e).find(".prev-page").show(),t==r?a("#"+e).find(".next-page").hide():a("#"+e).find(".next-page").show();var o,s,g=n,p=Math.ceil(g/2),l=Math.floor(g/2);r<g?(o=0,s=r):t>=1&&t<=p?(o=0,s=g):t+l>=r?(o=r-g,s=r):(o=t-p,s=t+l),a("#"+e+" .pager").children().each(function(){a(this).hasClass("page")&&a(this).hide()});for(var i=o;i<s;i++)o>0?(a("#"+e+" .prev-pages").show(),a("#"+e+" .prev-pages").data("value",o)):a("#"+e+" .prev-pages").hide(),a("#"+e+" .page[data-value='"+(i+1)+"']").show(),s<r?(a("#"+e+" .next-pages").show(),a("#"+e+" .next-pages").data("value",s+1)):a("#"+e+" .next-pages").hide();1==r?a("#"+e+" .last-page, #"+e+" .first-page").hide():0==r?a("#"+e+" .pager, #"+e+" .showing, #"+e+" .options").hide():(a("#"+e+" .pager, #"+e+" .showing, #"+e+" .options").show(),a("#"+e+" .last-page, #"+e+" .first-page").show())}function r(e,t,r,n,o,s,g,p){var l="",i=n*o-(o-1),h=n*o>r.length?r.length:n*o;if(r.length<=0){if(""==p)l+='<div class="dataError">There is nothing to show here.</div>';else l+=a("#"+p).html().format(["There are no Messages to display."]);return s||a("#"+e).hide(),l}a("#"+e).show(),a("#"+e+" .showing").html("Showing "+i+" to "+h+" of "+r.length+" total.");for(var c=n*o-o;c<n*o&&c!=r.length;c++){var u=[];a.each(g,function(a,e){u.push(r[c][e])}),l+=a("#"+t).html().format(u)}return l}a.fn.extend({paging:function(n){var o={data:{},contentHolder:"",template:"",errorTemplate:"",informationToShow:[],informationToRefineBy:[],perPage:10,pageLengths:[5,10,20,30,40,50],startPage:1,pagesToShow:5,showOptions:!0,showSearch:!0,alwaysShowPager:!0},s={currentPage:o.startPage,totalPages:0,currentData:n.data,refine:""};n=a.extend(o,n),(n=a.extend(s,n)).totalPages=Math.ceil(n.currentData.length/n.perPage),function(n,o){o.totalPages;e(n,o.currentData.length,o.perPage,o.pageLengths,o.showOptions,o.showSearch,o.refine),t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,o.perPage,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),a("#"+n).on("click",".page, .last-page, .first-page, .next-pages, .prev-pages",function(e){var s=parseInt(a(this).data("value")),g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("click",".next-page",function(e){var s=o.currentPage+1,g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("click",".prev-page",function(e){var s=o.currentPage-1,g=parseInt(a("#"+n+" .perPage").val());a("#"+n+" .page.current").removeClass("current"),a("#"+n+' .page[data-value="'+s+'"]').addClass("current"),t(n,s,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,s,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=s,a("#"+n).trigger("pagingChange")}),a("#"+n).on("change",".perPage",function(s){var g=parseInt(a(this).val());e(n,o.data.length,g,o.pageLengths,o.showOptions,o.showSearch,o.refine),o.totalPages=Math.ceil(o.currentData.length/g),t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,g,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),o.currentPage=o.startPage,a("#"+n).trigger("pagingChange")}),a("#"+n).on("keyup",".search",function(e){var s=parseInt(a("#"+n+" .perPage").val()),g=a(this).val();o.refine=g;var p=function(e,t,r){if(""==t)return;var n=t.toLowerCase();dataToKeep=[];for(var o=0;o<e.length;o++)a.each(r,function(a,t){if(null!=e[o][t]&&e[o][t].toLowerCase().indexOf(n)>=0)return dataToKeep.push(e[o]),!1});return dataToKeep}(o.data,g,o.informationToRefineBy);p||(p=o.data),o.currentData=p;var l=Math.ceil(o.currentData.length/s);o.totalPages=l,t(n,o.startPage,o.totalPages,o.pagesToShow),a("#"+o.contentHolder).html(r(n,o.template,o.currentData,o.startPage,s,o.alwaysShowPager,o.informationToShow,o.errorTemplate)),a("#"+n).trigger("pagingChange")}),a("#"+n).on("focusin",".search",function(){o.refineFocus=!0}),a("#"+n).on("focusout",".search",function(){o.refineFocus=!1})}(a(this).attr("id"),n)}})}(jQuery),String.prototype.format=function(){var a=arguments;return this.replace(/{(\d+)}/g,function(e,t){return void 0!==a[0][t]?a[0][t]:e})};
$(document).ready(function() {
var data = [{
"firstname": "John",
"lastname": "Smith"
}, {
"firstname": "Jane",
"lastname": "Doe"
}, {
"firstname": "James",
"lastname": "Smith"
}, {
"firstname": "Amanda",
"lastname": "Doe"
}, {
"firstname": "Billy",
"lastname": "Joe"
}];
$('#fs-table-table').paging({
data: data, //This is the data that is being used. It is using JSON data so you can pull from any source if you want.
contentHolder: 'fs-table-content', //The id for the area where you want the data to be displayed.
template: 'weeklyLessonTemplate', //The template that is being used to display the data.
errorTemplate: 'contentErrorTemplate', //The error template that is being used (optional)
informationToShow: ['firstname', 'lastname'], //The information that you want to show from the given data
informationToRefineBy: ['firstname', 'lastname'], //The information that you want to search on from the given data
perPage: 1, //Default number to show per page. (Since we have a small amount of data only show 1.)
pageLengths: [1, 2, 3, 4], //Options for number of items per page.
startPage: 1, //The default start page. (Better to leave as 1 but can be changed if desired).
pagesToShow: 4, //Number of pages to show at the top. If you have 10 pages it will show [...] when going above or below the this number.
showOptions: true, //Show the per page options.
showSearch: true, //Show the search bar.
alwaysShowPager: true //Show the pager even if there isn't any data. Should be true if showSearch is true otherwise there will be problems.
});
});
.pager span.current {
border: red;
border-radius: 5px;
font-weight: bold;
color: red;
}
.dataError {
width: 100%;
font-size: 20px;
text-align: center;
padding: 10px;
}
.searchBox {
width: 300px;
margin: 0 auto;
}
.searchBox .search {
width: 100%;
height: 30px;
}
.showing {
width: 100%;
text-align: center;
}
.dropdown:hover .dropdown-menu { display: block; }
.pager span {
border-radius: 5px;
border: #a6a6a8 1px solid;
padding: 5px 14px;
margin: 0 3px;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.pager span:hover { background-color: #ddd; }
.pager span.current:hover {
background-color: #fff;
cursor: default;
}
.pager {
padding-left: 0;
margin: 20px 0;
text-align: center;
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="fs-table-content"></div>
<div id="fs-table-table"></div>
<script type="text/template" id="weeklyLessonTemplate">
<div class="fs-table-row header">
<div class="fs-table-cell">
Course Name
</div>
<div class="fs-table-cell">
Lessons
</div>
</div>
<div id="fs-table-content">
<div class="fs-table-row">
<div class="fs-table-cell" data-title="Course Name">
{0}
</div>
<div class="fs-table-cell" data-title="Lesson">
<input type="radio" class="radio" name="weekly_lesson" value="{1}" />
<label for="{1}">{1}</label>
</div>
</div>
</div>
</script>

Vue: How do I generate a new instance of a div with a buttonclick?

I need to create a function that generates a new instance of a specific div (.container in the template) when a button (#addDiv) is clicked. The button should be the only thing visible on the webpage before that. How do I do?
I know that it may be possible to do this with document.appendChild. Is there a better way?
I am using toggle-function that works great, I have included it in the code to give you the whole picture.
Vue
Vue.component('dynamicdDvs', {
template: `
<div>
<div class="headerDiv">
<button class="addDiv" type="button" v-on:click="createDiv">Create</button>
</div>
<div class="container">
<div class="createdDiv">
<h2>I am dynamic!</h2>
<button class="minimize" v-on:click="expand">Make me smal</button>
</div>
<div class="createdDivMinimized" v-if="!displayDiv">
<p>I am a smal version of the created div!</p>
<button class="maximize" v-on:click="expand">Expand me</button>
</div>
</div>
</div>
`,
data:function () {
return {
displayDiv: false
}
},
methods: {
expand: function () {
this.displayDiv = !this.displayDiv;
},
createDiv: function() {
//The function that creates a new div, with the same code as
//.createdDiv and .createDivMinimized may be placed here
}
}
});
CSS
.headerDiv {
height: 100px;
width: 400px;
background-color: blue;
color: white
}
.createdDiv {
height: 300px;
width: 400px;
background-color: black;
color: white
}
.createdDivMinimized {
height: 300px;
width: 400px;
background-color: red;
color: white
}
HTML
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="parent">
<dynamicDivs></dynamicDivs>
</div>
So what you can do is set a number in data for the number of <div> elements and use v-for with a range. For example
data () {
return {
displayDiv: [false],
divs: 1
}
}
And in your template
<template v-for="n in divs">
<div class="createdDiv">
<!-- snip -->
<button class="minimize" v-on:click="displayDiv[n-1] = !displayDiv[n-1]">Make me small</button>
</div>
<div class="createdDivMinimized" v-if="!displayDiv[n-1]">
<!-- snip -->
</div>
</template>
and in your methods...
createDiv () {
this.divs++
this.displayDiv.push(false)
}

Owl carousel and knockout.js binding within foreach binding

He everyone, I know it is going to be specific question, but I have a problem using owl carousel with knockout.
<div class="row">
<div id="owl-example" class="owl-carousel" data-bind="foreach: ads">
<div class="ad-module">
<div data-bind="attr: { src: '/Content/images/' + Image }"></div>
<div data-bind="text: Title"></div>
<div data-bind="text: CityName"></div>
<div data-bind="text: CategoryName"></div>
</div>
</div>
</div>
If I delete owl-carousel class, everything works. And if I delete knockout foreach and enter images manually everything works. Did anyone ever had this problem before? Thanks.
You can call a specific function after you finish rendering the foreach items using:
<div data-bind="foreach: items, someOtherFunction">
The function that you want to call should be defined in ko.bindingHandlers
Here is a working example:
ko.bindingHandlers.owlCarouselInitiator = {
init: function() {
$('.owl-carousel').owlCarousel({
loop:true,
nav:true,
items : 3,
itemsDesktop : [1000,3],
itemsDesktopSmall : [900,3],
itemsTablet: [600,3]
})
}
};
ko.applyBindings({
items: ko.observableArray([
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"9",
"10"
])
});
body {
margin: 0;
padding: 0;
}
ul {
margin: 0;
padding: 0;
}
.owl-carousel .item {
height: 120px;;
background: #4DC7A0;
padding: 1rem;
list-style: none;
margin: 10px;
}
.owl-carousel .item h4 {
color: white;
text-align: center;
padding-top: 20px;
font-size: 25px;
line-height: 120px;
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/owl-carousel/1.3.3/owl.carousel.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/owl-carousel/1.3.3/owl.carousel.min.js"></script>
<ul class="owl-carousel" data-bind="foreach: items, owlCarouselInitiator">
<li class="item"><h4 data-bind="text: $data"></h4></li>
</ul>
If you need dynamically change items after view is rendered you can use custom knockout binding from https://github.com/OleksiiStepanov/KnockoutOwlCarousel2
Usage example:
<div class="owl-carousel owl-theme" data-bind="owlCarousel: {data: items, options:{margin:10, nav:true }}">
<div class="item" data-bind="text: $data"></div>
</div>
Live demo http://jsfiddle.net/s2reh01L/5/
You can also you the afterRender callback to run initialise your owl carousel once your foreach has rendered.
<ul data-bind="foreach: { data: myItems, afterRender: initOwlCarousel }">
<li data-bind="text: $data"></li>
</ul>

Can I use a handlebars template in my app.js file

I'm making a portfolio page and I want to have a picture that fades away and displays the text about the image behind it. Which I achieved hardcoding the data.
Like this.
index.html
<div class="col-sm-6">
<h4>Freelance Work</h4>
<img src="/images/andersen.png" class="portfolio_pic" id="test_pic">
<div id="test_text">
<p>Site for a structural engineer.</p>
<p><strong>Languages:</strong> JavaScript, HTML, CSS</p>
<p><strong>Other:</strong> Git, Bootstrap, GoDaddy Hosting</p>
</div>
<p>Andersen Engineering</p>
<p>GitHub Link</p>
</div>
styles.css
#test_text {
margin-top: -220px;
min-height: 210px
}
#test_pic {
max-height: 250px;
border: medium groove #660033;
}
app.js
$('.test_text').hide();
$('.test_pic').hover(function () {
$(this).stop().animate({
opacity: .1
}, 200);
$('.test_text').show();
}, function () {
$(this).stop().animate({
opacity: 1
}, 500);
$('.test_text').hide();
});
The problem is when I bring in the same info from my mongoose database, using this code
index.html
<div class="col-sm-6">
<div class="list-group" id="portfolio_items-list">
<script id="portfolio_items-template" type="text/x-handlebars-template">
{{#each portfolio_items}}
<h4>{{title}}</h4>
<img src={{image}} class="portfolio_pic" id="test_pic">
<div id="test_text">
<p>{{description}}</p>
<p><strong>Languages: </strong>{{language}}</p>
<p><strong>Frameworks: </strong>{{framework}}</p>
<p><strong>Libraries: </strong>{{library}}</p>
<p><strong>Database: </strong>{{database}}</p>
<p><strong>Other: </strong> {{other}}</p>
</div>
<p><a href={{sitelink}}>{{sitename}}</a></p>
<p><a href={{githublink}}>GitHub Link</a></p>
{{/each}}
</script>
</div>
</div>
app.js
var source = $('#portfolio_items-template').html();
var template = Handlebars.compile(source);
//get all database items
$.get(baseUrl, function (data) {
var dataHtml = template({ portfolio_items: data});
$("#portfolio_items-list").append(dataHtml);
});
then there aren't unique ID's for the test_pic and test_text id's so the javascript hide/show/opacity trick doesn't work. I was thinking if I could bring a template into the app.js and load each portfolio_items database id as a unique id for the hide/show/opacity js code, then it might work. the other alternative would be to make unique ids appear in the index/html file via the handlebars template and then copy the hide/show/opacity js code each time with that id hardcoded, but that would be very not DRY.
Any ideas?
Thanks!
The index of an {{each}} loop in handlebars is available by {{#index}} so you can do something like id="test-pic-{{#index}} to generate unique ids.
FWIW you can also accomplish the effects you are creating in just .css (see below).
.container {
width:50%;
height:250px;
overflow: hidden;
background: rgba(0, 0, 0, 0.5);
transition: all .3s ease;
}
.container:hover {
background: rgba(0, 0, 0, 0.1);
}
.text {
font-size: 2em;
opacity: 0;
transition: all .3s ease;
}
.container:hover .text {
opacity:1;
}
<div class="container">
<div class="text">
<p>hello</p>
<p>test</p>
</div>
</div>

Categories