Handlebars.js Partial Sub-Template generation - javascript

I am having issue with the Partials/Sub Template generation in the Handlebars.js.
I have used the registerPartials Method properly, but still it is giving some sort of issue in rendering. If I remove the partial template it would render the content properly.
Below is the code that I am using:
<!DOCTYPE html>
<html>
<head>
<title>Handlebars.js example</title>
</head>
<body>
<div id="placeholder">This will get replaced by handlebars.js</div>
<script type="text/javascript" src="handlebars.js"></script>
<script id="myTemplate" type="x-handlebars-template">
{{#each allShoes}}
<li>
<span> {{name}} - </span> price: {{price}}
{{> description}}
</li>
{{/each}}
</script>
<script id="shoe-description" type="x-handlebars-template">
<ul>
<li>{{color}}</li>
<li>{{size}}</li>
</ul>
</script>
<script type="text/javascript">
var source = document.getElementById("myTemplate").innerHTML;
var template = Handlebars.compile(source);
// Register the Partial
//Handlebars.registerPartial("description", $("#shoe-description").html());
var shoesData = {
allShoes:[
{name:"Nike", price:199.00,color:"black", size:10},
{name:"Loafers", price:59.00, color:"blue", size:9},
{name:"Wing Tip", price:259.00, color:"brown", size:11}
]
};
Handlebars.registerPartial("description", $("#shoe-description").html());
document.getElementById("placeholder").innerHTML = template(shoesData);
</script>
</body>
</html>
Is there any issue with the registerPartial?
Any help is appreciated.
Thanks,
Ankit Tanna

I'd guess that your rendering issues are a side effect of asking the browser to render invalid HTML. Your HTML ends up with, more or less, this structure:
<div>
<li>
<ul>...</ul>
</li>
...
</div>
But an <li> must have a <ul>, <ol>, or <menu> as its parent. I quote the specification:
Permitted parent elements
ul, ol, menu
So having a <div> as the parent of an <li> is invalid and the browser may rewrite your not-quite-HTML to make it valid HTML. That correction could be making a mess of your inner lists. Fix your HTML and try again:
<script id="myTemplate" type="x-handlebars-template">
<ul>
{{#each allShoes}}
...
{{/each}}
</ul>
</script>
Demo: http://jsfiddle.net/ambiguous/R23Ak/

Related

Change loaded content in an HTML file with javascript

Some content, in this case a navbar (navbar.php), is loaded into the index.html by Javascript. Now I want to change a navbar list item from "Home" to "Something else" using Javascript. But it seems that the script can not see the loaded content. The console gives an „document.getElementById(...) is null“ error. Following the code:
index.html
<!DOCTYPE html>
<html lang="de">
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(function() {
$("#navbar").load("navbar.php");
return false;
});
</script>
</head>
<body>
<div class="container">
<div class="row">
<header>
<div id="navbar">
</div>
</header>
<main>
</main>
<footer>
</footer>
<script>
let myChange = document.getElementById("change").innerHTML;
myChange = "<a href='somethingelse.html'>Something else</a>";
</script>
</body>
</div>
</div>
</html>
navbar.php
<div>
<ul>
<li id="change">Home</li>
<li >Logout</li>
</ul>
</div>
Any idea what is wrong in the code?
Thanks a lot in advance.
You would need to use the load's callback function for load to know when the content has been added to the document.
$("#navbar").load("navbar.php", function() {
const myChange = document.getElementById("change");
myChange.innerHTML = "<a href='somethingelse.html'>Something else</a>";
});

Use Shopify/draggable with Alpine.js x-for directive

I'm trying to make the sortable plugin from Shopify working with Alpine.js but when I drag and drop the items, it generate the error in the console
"Alpine Error: 'ReferenceError: framework is not defined'
Expression: 'framework'
Element: "<li x-text="framework" tabindex="0" style="" class="draggable-source--is-dragging">springs</li>
Here's a reproducible example
https://codepen.io/cbaconnier/pen/bGgxyWE?editors=1011
<html>
<head>
</head>
<body>
<div x-data="{frameworks: ['laravel', 'rails', 'django', 'springs']}">
<ul>
<template x-for="framework in frameworks" :key="framework">
<li x-text="framework"></li>
</template>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.8.2/dist/alpine.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#shopify/draggable#1.0.0-beta.12/lib/sortable.js"></script>
<script>
const sortable = new Sortable.default(document.querySelectorAll('ul'), {
draggable: 'li'
});
</script>
</body>
</html>
I know there's some homemade dragable/sortable that have been done with Alpine.js but since I'm already using it with Livewire on this project and some other, it would be nice to also make it works.
Even though I would like to keep Shopify/draggable I have resigned to use SortableJS/Sortable that seems to works quit well.
<html>
<head>
</head>
<body>
<div
x-data="{frameworks: ['laravel', 'rails', 'django', 'springs']}"
x-init="Sortable.create($refs.items)"
>
<ul x-ref="items">
<template x-for="framework in frameworks" :key="framework">
<li x-text="framework"></li>
</template>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.8.2/dist/alpine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.13.0/Sortable.min.js"></script>
</body>
</html>

numbers in li element tag not working with vue.js

when I tried to run this vue code,
<!DOCTYPE html>
<html>
<head>
<title>My first Vue app</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="shopping-list">
<ol id="shopping-list" v-for="item of items">
<li>{{ item }}</li>
</ol>
</div>
<script>
var app = new Vue({
el: "#shopping-list",
data: {
items: ["VR Headset", "Some Games"]
}
});
</script>
</body>
</html>
The output would show that the first item had a 1. in front of it, but the second item also has a one in front of it.
Expected Result:
Actual Result:
Also, notice how the actual result is less compact than the actual result, which I don't like. Help would be greatly appreciated.
The v-for loops over elements based on the current element you have the v-for on. In your case - you didn't create multiple <li> elements, but instead you created multiple <ol> elements.
You can change your code to this instead:
<ol id="shopping-list">
<li v-for="item of items">{{ item }}</li>
</ol>

Directives in angular js not working properly

I have two directives in my first22 module mycustomer1 and mycustomer. Problem is mycustomer directive is not called ? Can anyone explain me what i am doing wrong here?
Below is my html
<!DOCTYPE html>
<html ng-app="first22">
<head>
<link rel="icon" type="image/png" href="globe/images/correct.png"/>
<link rel="stylesheet" type="text/css" href="globe/css/style.css"/>
<script type="text/javascript" src="globe/script/jquery.js"></script>
<script type="text/javascript" src="globe/script/angular.js"></script>
<script type="text/javascript" src="globe/script/mainscope.js"></script>
<script type="text/javascript" src="globe/script/angular-route.js"></script>
</head>
<body >
<div id="maincontainer" ng-controller="nameListCtrl">
<div id="header">
<div id="headtext">HTML5 SAMPLE</div>
<mycustomer/>
<mycustomer1/>
</div>
<div id="sidebar" >
<first-directive></first-directive>
<ul id="mainmenu" style="">
<li ng-repeat="item1 in content"><a style="color:grey;" id="{{item1.title }}" class="asa" ng-click="show=!show" ng-model="checked" ng-href="#/{{item1.title }}">{{item1.title }}</a>
<ul ng-show="show " ng-if="item1.subitems" style="text-align:left;margin-left:25px;">
<li ng-repeat="category in item1.subitems" >
{{ category.title }}
</li>
</ul>
</li>
</ul>
</div>
<div id="content">
<div id="content_flow" ng-view="">
</div>
</div>
<div id="Interactive_content">
<div id="Interactive_content_flow">
<div id="close">
</div>
</div>
</div>
</div>
</body>
</html>
And my angular directive declaration below
var first2 = angular.module('first22', []);
first2.directive('mycustomer1',function()
{
return{
restrict:'E',
replace: 'true',
template:'<h1>aaaaaaaaaaaaaaaaaaaaaa</h1>',
link: function()
{
alert("I'm working");
}
}
})
first2.directive('mycustomer', function()
{
return {
restrict: "E",
replace: 'true',
template: '<h3>Hello World!!</h3>',
link: function()
{
alert("I'm working 1");
}
}
});
Directive names, when being declared should be in camelCase
first2.directive('myCustomer', function() { ... }
When using them in HTML elements, you must use hyphenated-lower-case
<my-customer></my-customer>
Working jsFiddle Demo
As Rene pointed out above, it is only a convention and it works without the camel case too. Raghav code works because he used empty closing tags like this "" and not ""
The issue is that "mycustomer" directive has replace clause in definitation and self-closing tags work only for a few some kinds of tags, browser doesn't close the "mycustomer" tag at all until the point it's parent, div in this case, closes so "mycustomer1" shows up inside the "mycustomer" tag so when "mycustomer" directive runs, it replaces it content which is now "mycustomer1" and hence "mycustomer1" doesn't actually run at all.
In essence, the code by OP really looks like below so when "mycustomer" runs, it removes "mycustomer1" from the HTML because of the "replace" in mycustomer's directive definition.
<div>
<mycustomer>
<mycustomer1></mycustomer>
</mycustomer>
<div>
The reason Seminda's solution works is again that the individual "mycustomer" and "mycustomer1" are included in parent divs so they close right before the div close themselves.
For directives inside directive, checkout "transclude" property working with replace.
Place your directive in the code like below. then it will work.
<div>
<mycustomer />
</div>
<div>
<mycustomer1 />
</div>
Working demo

Angularjs binding does not work when injecting html

I tried to look at documentation but it seems i am missing something. I am trying to inject html which is bound to a json. It works fine if the html is declared but when i inject it despite calling the $compile it is not working. Here is the code
<!DOCTYPE html>
<html ng-app>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"> </script>
<script src="todo.js"></script>
<script>
function TodoCtrl($scope)
{
$scope.todos = [{text:'LearnAngularJS'}, {text:'Unlearn Angular'},];
}
$(document).ready(function()
{
$('#div1').html(
$compile('<div ng-controller="TodoCtrl"><ul><li ng-repeat="todo in todos" compile="text">{{todo.text}}<li><ul><div>')(scope));
});
</script>
</head>
<body>
<div ng-controller="TodoCtrl">
<ul>
<li ng-repeat="todo in todos">
{{todo.text}}
<li>
<ul>
</div>
<div id="div1">
<div>
</body>
</html>
http://plnkr.co/edit/NQQBgQKBWEqKHxGwnI0h?p=preview
As Ajay pointed out, you'll have to associate one of your scope with template.

Categories

Resources