How to feed template to HTML from Javascript? Sounds confusing? I'll try my best to explain after put all the codes in here...
I have index.html here:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inject Template</title>
</head>
<body>
<div id="app">
<div v-html="injectHTML" v-if="injecting"></div>
<div id="chart">
<ol>
<li id="card-wrapper">
<div id="card">
<employee-card :info="emp.chart[1]"></employee-card>
</div>
</li>
</ol>
</div>
</div>
<!-- Vue.js Component: Employee Card Template -->
<script type="text/x-template" id="employee-card-template">
<div class="employee-wrapper" v-if="info" :id="info.id">
<a class="node" :href="'#'+info.id">
<div class="empinfo">
<p class="name">{{info.name}}</p>
<p class="office">{{info.office}}</p>
<p class="title">{{info.title}}</p>
</div>
</a>
</div>
</script>
<script src="lib/vue/dist/vue.js"></script>
<script src="js/app.js"></script>
</body>
</html>
and here is app.js
const app = new Vue({
el: "#app",
data: {
emp: [], //collect employee information from JSON
injectHTML: '',
injecting: false,
key: 0
},
watch: {
key: function () {
app.$forceUpdate();
app.injecting = true;
}
},
created: function () {
this.loadEmpJson();
setTimeout(() => { this.inject(); }, 500);
},
methods: {
loadEmpJson: function () {
const xhr_oho = new XMLHttpRequest();
xhr_oho.open('GET', 'data/employee.json', true);
xhr_oho.responseType = 'text';
xhr_oho.send();
xhr_oho.onreadystatechange = function () {
console.log(`xhr_oho.readyState: ${xhr_oho.readyState}`)
console.log(`xhr_oho.status: ${xhr_oho.status}`)
console.log(`xhr_oho.statusText: ${xhr_oho.statusText}`)
}
xhr_oho.onload = function () {
app.emp = JSON.parse(xhr_oho.responseText);
}
},
inject: function () {
this.injectHTML =
`<div id="chart">
<ol>
<li id="card-wrapper">
<div id="card">
<employee-card :info="emp.chart[0]"></employee-card>
</div>
</li>
</ol>
</div>`
setTimeout(() => { this.key++; }, 500);
}
}
});
Vue.component('employee-card', {
template: '#employee-card-template',
props: {
info: { type: Object, default: () => ({}) }
}
})
lastly, the excerpt employee.json
{
"description": "ABC Company Organizational Chart",
"chart": [
{
"name": "Jimmy Moore",
"office": "Front Office",
"title": "CEO/Owner"
},
{
"name": "Betty Kahoolawe",
"office": "Front Office",
"title": "President"
},
{
"name": "David Merrill",
"office": "Front Office",
"title": "Vice President",
"assistants": [
{
"name": "Amanda Cochran",
"office": "Front Office",
"title": "Executive Assistant"
},
{
"name": "Savannah Clewiston",
"office": "Front Office",
"title": "Budget Officer"
}
]
}
]
}
I would like to be able to feed multi marker template (employee-card) dynamically from app.js. Reason for this, I will have a recursive collecting data from JSON file and elaborate the employee-wrapper template depending on data from JSON. Grouping by the employees such as office, division, component, and branch. Also grouping by the employees under each supervisor where it can be expand and collapse those employees under the supervisor.
But the point I need to be able to feed the from app.js
You can see the output:
1.
1. Betty Kahoolawe
Front Office
President
which should be:
1. Jimmy Moore
Front Office
CEO/Owner
2. Betty Kahoolawe
Front Office
President
Your help is greatly appreciated! Thank you.
Related
I am pretty new in Javascript and I have problem. Currently I am working on project, that is actually my practice project and I'm trying to make shopping cart page. My problem is with JSON file, I don't know how to render it (show it within HTML in browser), I have local JSON file with some products. Here is my code of main page, app.js(where is my function for JSON file) and JSON file with products
HTML file
<!DOCTYPE html>
<html lang="en">
<head>
<title>Shopping Cart</title>
<meta charset="utf-8" />
<meta name="description" content="cobe" />
<meta name="author" content="cobe" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../style/style.css" />
</head>
<body>
<main class="main-wrapper">
<div class="items">
<div class="item">
<div class="image">
<img src="" alt="" class="img">Image</img>
</div>
<h2 class="item-name">Name of item</h2>
<h3 class="price">Price</h3>
<button class="button">Add item</button>
</div>
<div id="products" class="list"></div>
</div>
</main>
<script type="text/javascript" src="../products.json"></script>
<script type="text/javascript" src="../app.js"></script>
app.js file
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
let response = JSON.parse(xhttp.responseText);
let products = response.products;
let output = '';
for (let i = 0; i < products.length; i++) {
output += '<li>' + products[i].name + '</li>';
}
document.getElementById('products').innerHTML = output;
}
};
xhttp.open("GET", "products.json", true);
xhttp.send();
and JSON file which is called products.json
{
"products": [
{
"id": 1,
"name": "Eggs",
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/W1ymDizfe679XsfX9uP8A5bU/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"price": {
"amount": 7.99,
"currency": "Kn",
"measureUnit": "Kom"
}
},
{
"id": 2,
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/b1qEMnNGbwiwV5cWysofPoqz/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"name": "Milk",
"price": {
"amount": 4.99,
"currency": "Kn",
"measureUnit": "Kom"
}
},
{
"id": 3,
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/1avpwnxKAEqEpTf1k3VCbBbg/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"name": "Cheese",
"price": {
"amount": 44.99,
"currency": "Kn",
"measureUnit": "Kg"
}
}
]
}
So my question is what should I write in HTML file so I could get let's say name of product from JSON file into my div which is declared in HTML file for name or am I missing some more JS functions? Currently my page is blank because I couldn't resolve how to get everything from JSON file.
HTML files are in views folder, app.js and products.json are outside of views folder.
Thanks!
Try using a function to generate the template and set the innerHTML property.
You can use this populateProducts function once you have got the response JSON from the API. This will generate the template and will update the DOM.
var myData = {
"products": [
{
"id": 1,
"name": "Eggs",
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/W1ymDizfe679XsfX9uP8A5bU/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"price": {
"amount": 7.99,
"currency": "Kn",
"measureUnit": "Kom"
}
},
{
"id": 2,
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/b1qEMnNGbwiwV5cWysofPoqz/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"name": "Milk",
"price": {
"amount": 4.99,
"currency": "Kn",
"measureUnit": "Kom"
}
},
{
"id": 3,
"image": "https://d17zv3ray5yxvp.cloudfront.net/variants/1avpwnxKAEqEpTf1k3VCbBbg/7b27a910a7194c812eacf34700e38dcab3abed02f30837d1dad313c5651bb5fa",
"name": "Cheese",
"price": {
"amount": 44.99,
"currency": "Kn",
"measureUnit": "Kg"
}
}
]
};
function populateProducts() {
var template = '';
for(let index = 0; index < myData.products.length; index++) {
template +=
"<div>Name: " + myData.products[index].name + "</div>" +
"<div>Image: <img class='my-image' src='" + myData.products[index].image + "' /></div>"+
"<div>Amount: " + myData.products[index].price.amount + "</div>" +
"<div>Currency: " + myData.products[index].price.currency + "</div>" +
"<div>MeasureUnit: " + myData.products[index].price.measureUnit + "</div>";
}
document.getElementById('item-wrapper').innerHTML = template;
}
populateProducts();
.my-image {
max-width: 50px;
}
<main class="main-wrapper">
<div id="item-wrapper"></div>
</main>
If you're able to use a templating system such as Handlebars.js, you could convert the repeated part of your HTML (the item div) into a template and then populate it with the data. Adapting the 'Getting Started' example from the Handlebars page, the template would look something like:
<script id="item-template" type="text/x-handlebars-template">
{{#each products}}
<div class="item">
<div class="image">
<img src="{{image}}" alt="" class="img">Image</img>
</div>
<h2 class="item-name">{{name}}</h2>
<h3 class="price">{{price.amount}}</h3>
<button class="button">Add item</button>
</div>
{{/each}}
</script>
Then in the script you would register the template:
const source = document.getElementById("item-template").innerHTML;
const template = Handlebars.compile(source);
...and then inside your HTTP request, you can pass the data to the template and it'll return HTML which you can add to the DOM as you wish:
const html = template(context);
I'm using a JS plugin called EasyAutocomplete to handle advanced autosuggestion on my website. It supports remote data sets (JSON, XML, plain text) and uses ajax method calls to search, sort and match the response phrase.
I'm trying to write a custom match formula, which it allows me to do, but would love some help writing this out.
Right now, as you type, it searches for any part of a word/phrase for what you're typing. I'd like to have it only check the beginning of each word in a single or multi-word phrase.
Let's say my remote data set contains:
"Market Street"
"Market Thestreet Lane"
"Street South Road"
If my search is "Street", by the plugin's default functionality, all 3 results will show, because the word "street" is part of each of those 3 results. (Demo Below)
I found a similar question to mine on the plugin's Github repo (and the answer from the plugin author), but that question was for matching only the beginning of each result item (not each word in each result item). So if my search is "Street", only the third result will show. (Demo Below)
My question is for a match formula that searches the beginning of any word in a result item. So, if my search is "Street", the first and third result will show.
Here is how the plugin functions by default (I've commented out the custom match formula):
jQuery(document).ready(function($) {
var options = {
data: [
{"name": "Market Street", "parent": "Dog Management", "link": "https://marketstreet.com"},
{"name": "Market Thestreet Lane", "parent": "Dog Management", "link": "https://marketlane.com"},
{"name": "Street South Road", "parent": "Cat Management", "link": "https://streetsouthroad.com"}
],
getValue: "name",
list: {
match: {
enabled: true,
/*
method: function(element, phrase) {
if(element.indexOf(phrase) === 0) {
return true;
} else {
return false;
}
}
*/
},
onSelectItemEvent: function() {
var selectedItemValue = $("#companies").getSelectedItemData().parent;
var selectedItemLink = $("#companies").getSelectedItemData().link;
$("#company_result").html('Contact '+selectedItemValue+'').trigger("change");
},
},
template: {
type: "description",
fields: {
description: "parent"
}
}
};
$("#companies").easyAutocomplete(options);
});
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css'>
<link rel='stylesheet' href='https://d3vv6lp55qjaqc.cloudfront.net/items/040r1I2Y1K3T3w3L3i3E/easy-autocomplete.css'>
<script src='https://code.jquery.com/jquery-1.11.2.min.js'></script>
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<script src='https://d3vv6lp55qjaqc.cloudfront.net/items/2Q0s1P3D0D2i3u0M1m1x/jquery.easy-autocomplete.min.js'></script>
<div class="container">
<br>
<div class="row">
<div class="col-md-8 col-offset-3">
<p>Search for "Street"</p>
<form style="text-align: center; margin: 0 auto;" onkeypress="return event.keyCode != 13;">
<input class="form-control" id="companies" placeholder="Type your resort property name..."/>
<div id="company_result"></div>
</form>
</div>
</div>
</div>
Here is that custom match formula that only matches if the result item begins with the search phrase:
jQuery(document).ready(function($) {
var options = {
data: [
{"name": "Market Street", "parent": "Dog Management", "link": "https://marketstreet.com"},
{"name": "Market Thestreet Lane", "parent": "Dog Management", "link": "https://marketlane.com"},
{"name": "Street South Road", "parent": "Cat Management", "link": "https://streetsouthroad.com"}
],
getValue: "name",
list: {
match: {
enabled: true,
method: function(element, phrase) {
if(element.indexOf(phrase) === 0) {
return true;
} else {
return false;
}
}
},
onSelectItemEvent: function() {
var selectedItemValue = $("#companies").getSelectedItemData().parent;
var selectedItemLink = $("#companies").getSelectedItemData().link;
$("#company_result").html('Contact '+selectedItemValue+'').trigger("change");
},
},
template: {
type: "description",
fields: {
description: "parent"
}
}
};
$("#companies").easyAutocomplete(options);
});
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css'>
<link rel='stylesheet' href='https://d3vv6lp55qjaqc.cloudfront.net/items/040r1I2Y1K3T3w3L3i3E/easy-autocomplete.css'>
<script src='https://code.jquery.com/jquery-1.11.2.min.js'></script>
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<script src='https://d3vv6lp55qjaqc.cloudfront.net/items/2Q0s1P3D0D2i3u0M1m1x/jquery.easy-autocomplete.min.js'></script>
<div class="container">
<br>
<div class="row">
<div class="col-md-8 col-offset-3">
<p>Search for "Street"</p>
<form style="text-align: center; margin: 0 auto;" onkeypress="return event.keyCode != 13;">
<input class="form-control" id="companies" placeholder="Type your resort property name..."/>
<div id="company_result"></div>
</form>
</div>
</div>
</div>
Thank you!
method: function(element, phrase) {
return !!element.toLowerCase().split(" ").filter((word) => word.indexOf(phrase.toLowerCase()) === 0).length;
}
This function:
Makes the element lowercase (no capitalization woes)
Splits it into its words
Filters out any words that don't start with the given input
If the filtered array has any elements in it, it must match. Otherwise, it doesn't. That's what the .length check there is for.
I am using ng-repeat directive but it does not showing me value. Here is my code
JS File:
var artist = angular.module('artistApp',[]);
artist.controller('artistController',['$scope',function($scope){
$scope.author =
{
"name":"Barot Bellingham",
"shortname":"Barot_Bellingham"
},
{
"name":"Jonathan G. Ferrar II",
"shortname":"Jonathan_Ferrar"
},
{
"name":"Hillary Hewitt Goldwynn-Post",
"shortname":"Hillary_Goldwynn"
}
}]);
HTML file:
<head>
<meta charset="utf-8">
<title>Angular Demo</title>
<script src="angular/angular.min.js"></script>
<script src="js/controllers.js"></script>
</head>
<body>
<div ng-controller="artistController">
<ul>
<li ng-repeat="item in author">
{{item.name}}
</li>
</ul>
</div>
</body>
Where is the mistake that i m doing wrong here.
You're missing the opening bracket to the author array
$scope.author =
{
Needs to be:
$scope.author =
[{
in JS
$scope.author =
[{
"name":"Barot Bellingham",
"shortname":"Barot_Bellingham"
},
{
"name":"Jonathan G. Ferrar II",
"shortname":"Jonathan_Ferrar"
},
{
"name":"Hillary Hewitt Goldwynn-Post",
"shortname":"Hillary_Goldwynn"
}];
HTML
<li ng-repeat="item in author track by $index">
{{item.name}}
</li>
Replace the last '}' with ']'
Working Plunker
Corrected JSON:
[{
"name":"Barot Bellingham",
"shortname":"Barot_Bellingham"
},
{
"name":"Jonathan G. Ferrar II",
"shortname":"Jonathan_Ferrar"
},
{
"name":"Hillary Hewitt Goldwynn-Post",
"shortname":"Hillary_Goldwynn"
}
]
I'm taking tutorial in CodeSchool about angular and I try to create my own experiment in html5 and angular new version in vs2012.
I try to test angular repeat but the problem is HTML5 can't render my angular.
When I try to run my page, the repeater only show the angular statement {{item.name}}:{{item.quantity}} not the result. Why? -"show code below"
Angular script :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
application.js :
<script type="text/javascript" src="Scripts/application.js"></script>
$(function () {
var app = angular.module('zaskarCorp', []);
app.controller('kirito', function ($scope) {
$scope.items = [{
"name": "dual sword",
"quantity": 2
}, {
"name": "gun",
"quantity": 1
}, {
"name": "laser sword",
"quantity": 1
}];
});
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" data-ng-app="zaskarCorp">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<script type="text/javascript" src="Scripts/application.js"></script>
</head>
<body data-ng-controller="kirito">
<ul>
<li data-ng-repeat="item in items">
<span>{{item.name}}:{{item.quantity}}</span>
</li>
</ul>
</body>
</html>
As you can see I add data- in my angular because I use html5. -"I hate warnings"
Your code has a number of typos and errors:
funtion instead of function
agular instead of angular
no jQuery included, but you call $(function(){...})
Here's a plunker with your code working.
Also, for future reference, if you remove .min from the angular source, it makes it easier to debug.
Please add this directive to your body tag:
data-ng-app="zaskarCorp"
Also, you have some misspellings in your javascript code.
Without using jQLite your code will look like this:
var app = angular.module('zaskarCorp', []);
app.controller('kirito', function ($scope) {
$scope.items = [
{
"name": "dual sword",
"quantity": 2
},
{
"name": "gun",
"quantity": 1
},
{
"name": "laser sword",
"quantity": 1
}];
});
Full code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" data-ng-app="zaskarCorp">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<script>
var app = angular.module('zaskarCorp', []);
app.controller('kirito', function($scope) {
$scope.items = [{
"name": "dual sword",
"quantity": 2
}, {
"name": "gun",
"quantity": 1
}, {
"name": "laser sword",
"quantity": 1
}];
});
</script>
</head>
<body data-ng-controller="kirito">
<ul>
<li data-ng-repeat="item in items">
<span>{{item.name}}:{{item.quantity}}</span>
</li>
</ul>
</body>
</html>
I have a defined a basic controller which has a function called setSector (at the bottom)
function AppCtrl ($scope) {
$scope.sectors =
{
"Sector": [
{
"sectorDesc": "London and South East",
"sectorCode": "LSE",
"SectorPPM": {
"Total": "10329",
"OnTime": "9195",
"Late": "1134",
"CancelVeryLate": "206",
"PPM": {
"rag": "A",
"text": "89"
},
"RollingPPM": {
"trendInd": "-",
"rag": "R",
"text": "83"
}
}
},
{
"sectorDesc": "Long Distance",
"sectorCode": "LD",
"SectorPPM": {
"Total": "1383",
"OnTime": "1159",
"Late": "224",
"CancelVeryLate": "68",
"PPM": {
"rag": "R",
"text": "83"
},
"RollingPPM": {
"trendInd": "+",
"rag": "G",
"text": "92"
}
}
},
{
"sectorDesc": "Regional",
"sectorCode": "REG",
"SectorPPM": {
"Total": "5348",
"OnTime": "4678",
"Late": "670",
"CancelVeryLate": "196",
"PPM": {
"rag": "R",
"text": "87"
},
"RollingPPM": {
"trendInd": "=",
"rag": "R",
"text": "87"
}
}
},
{
"sectorDesc": "Scotland",
"sectorCode": "SCO",
"SectorPPM": {
"Total": "2026",
"OnTime": "1861",
"Late": "165",
"CancelVeryLate": "41",
"PPM": {
"rag": "A",
"text": "91"
},
"RollingPPM": {
"trendInd": "+",
"rag": "G",
"text": "94"
}
}
}
]
}
$scope.currentSector = null;
$scope.setSector = function (sectorCode) {
$scope.currentSector = $scope.sectors[sectorCode];
};
}
which is called from my index file.
<html ng-app>
<head>
<title>PPM Viewer</title>
<script type="text/javascript" src="js/lib/angular.min.js"></script>
<script type="text/javascript" src="js/lib/angular-resource.min.js"></script>
<script type="text/javascript" src="js/controllers/app.js"></script>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
</head>
<body>
<div class="container" ng-controller="AppCtrl">
<h1>PPM Dashboard</h1>
<ul>
<li ng-repeat="sector in sectors.Sector">
{{sector.sectorCode}} - {{sector.sectorDesc}}
</li>
</ul>
<p>
Current sector : {{currentSector.sectorDesc}}
Current code : {{currentSector.sectorCode}}
</p>
</div>
</body>
When you click on the sectors in the UL list, the name of the clicked on sector is supposed to appear at the bottom, but for some reason the function is not passing back anything.
I am sure it is due to needing to specify the $scope.sectors.Sector somewhere in the function. but nothing I try will work. I am still quite new to angular and scopes, and think that I need to force the scope to go to a deeper level.. just not sure how
Can anyone advise how I can make the function... function! =)
Many thanks
So neater way of doing this would be to use the $index functionality of Angular. Try changing your code to:
HTML
<ul>
<li ng-repeat="sector in sectors.Sector">
{{sector.sectorCode}} - {{sector.sectorDesc}}
</li>
</ul>
JS
$scope.setSector = function (index) {
$scope.currentSector = $scope.sectors.Sector[index];
};
$index in an ng-repeat states the index of an item in an array, which you can use in the javascript to select the correct sector from your array.
http://docs.angularjs.org/api/ng.directive:ngRepeat
You're setting $scope.currentSector, instead of .sectorDesc
So either change your function or template:
Template:
Current sector : {{currentSector}}
Or function:
$scope.currentSector = {};
$scope.setSector = function (sectorCode) {
$scope.currentSector.sectorDesc = $scope.sectors[sectorCode];
};