Hogen.js - Load nested template with JS - javascript

I got a postings template (Hogen.js) were I load data (api call from Laravel 5.3) into it.
I managed to load, compile and render the template and the data correctly.
Problem:
I have jquery/vanilla js scripts that need to work with the template and the data but somehow this JS is completely ignored by the rendered template and it doesn't work (onClick, other ajax calls etc.).
My load/render JS:
var $page = 1;
var source = $("#postTemplate").html();
var template = Hogan.compile(source);
$.ajax({
url: '/api/postings',
data: { page: $page} ,
type: 'POST',
success: function(data) {
var output = template.render(data);
$('.posts-container').prepend(output);
}
});
My Template:
<script id="postTemplate" type="text/x-hogan-template">
#{{#posts.data}}
<div class="post">
<div class="image">
<img src="#{{ imageURL }}" alt="post image" />
</div>
<div class="info">
<div class="like-count" data-like-id="#{{ id }}">
more html
</div>
</div>
#include('partials.comments')
</div>
#{{/posts.data}}
</script>
I include a partial from laravel with my "comment" code that needs to be execuded aswell (fadeIn, ajaxacalls,submit etc.)
Is it possible, that I cann ot execute my JS with the newly rendered template or DOM, because it's not available at document.ready?
Do I need to switch my template engine? Any other way to make this work?
JSON:
{
"success": true,
"posts": {
"total": 46,
"per_page": 20,
"current_page": 3,
"last_page": 3,
"next_page_url": null,
"prev_page_url": "http://localhost/api/postings?page=2",
"from": 41,
"to": 46,
"data": {
"40": {
"id": 6,
"name": " ",
"imageURL": "",
"city": "Spanien",
"country": "",
"created_at": "2018-03-11 09:40:25",
"profilePictureURL": null,
"social_src": 0,
"mediumImageURL": null
}
}
}
}
I stripped it down a bit!

You cannot use
#include('partials.comments')
in your hgan.js template. Hogan is (almost) logicless. It is for binding JSON to HTML templates, it is not capable or intended for this use.
Partials can only be used like folows:
var partialText = "normal text but can use {{foo}} is from a variable";
var p = Hogan.compile(partialText);
var text = "This template contains a partial ({{>partial}})."
var t = Hogan.compile(text);
var s = t.render({foo: chickens}, {partial: p});
is(s, "This template contains a partial (normal text but we can use chickens. is a variable).", "partials work");
Basically {{>partial}} can be used to nest another precompiled template.

Related

Replace jQuery with vanilla JS when parsing JSON, and other improvements

I would like get rid of jQuery for this simple task, but I don't know how to use vanilla JS to do the job. The page works fine, but I recognize that it is a mess, and I would like to improve the invisible, under the hood code.
I am a complete noob, I will try to explain what I've done but I need your help to simplify as much as possible and clean the code (one function only / alternative to javascript in "href" / everything else that comes to mind). And to get rid of a 88kB .js file just to call a function.
The web page contains two links that point to local Icecast streams.
When one selects a stream by clicking a link,
the common audio player loads the corresponing source URL (function changeStream());
the link is highligted and every other link returns to the default CSS (function changeBg());
the variable number is set to the correspondibg element number to allow title parsing;
the jQuery function getTitle() is executed.
Additional notes:
HTML IDs with "*-js" means that they are modified by a javascript function;
I may have mispelled something below, I have rewritten variables and other parts with easier to understand names;
Getting rid of jQuery is my priority, but other improvements are well accepted.
Thank you in advance
The webpage contains is
<!doctype html>
<html lang="en">
<head>[...]</head>
<body>
<div class="links">
<a id="/sourceA-js" class="sourceLink"
href="javascript:changeStream('/radio/sourceA'); changeBg('/sourceA-js'); var number=0; getTitle();">
<span class="sourceText">Stream A</span></a>
<a id="/sourceB-js" class="sourceLink"
href="javascript:changeStream('/radio/sourceB'); changeBg('/sourceB-js'); var number=1; getTitle();">
<span class="sourceText">Stream B</span></a>
</div>
<div id="currentTrackInfo">
<p>Track: <span id="currentTrackTitle-js">Please select a radio stream</span>
</p>
<audio id="radio-js" class="radioPlayer" controls>
<source src="" type="audio/mpeg">
</audio>
</div>
<script>
function changeBg (streamId) {
var boxes = document.getElementsByClassName('sourceLink'),
i = boxes.length;
while (i--) {
boxes[i].removeAttribute('style');
}
document.getElementById(streamid).setAttribute('style', 'color:grey;background-color:red;');
}
function changeStream (stream) {
document.getElementById('radio-js').pause();
document.getElementById('radio-js').setAttribute('src', stream);
document.getElementById('radio-js').load();
document.getElementById('radio-js').play();
}
</script>
<script src="/static/js/jquery.js"></script>
<script>
function getTitle () {
jQuery.get('status-json.xsl', {}, function (response) {
$('#currentTrackTitle-js').html(response.icestats.source[number]['title']);
document.title = response.icestats.source[number]['title'];
});
}
gettitle();
setInterval(gettitle, 15000);
</script>
</body>
</html>
The parsed file, status-json.xsl, contains
{
"icestats": {
"admin": "mail",
"host": "domain",
"location": "name",
"server_id": "version",
"server_start": "humandate",
"server_start_iso8601": "computerdate",
"source": [
{
"audio_info": "bitrate=320",
"bitrate": 320,
"genre": "Jazz",
"listener_peak": 2,
"listeners": 1,
"listenurl": "address",
"server_description": "streamdescription",
"server_name": "streamname",
"server_type": "audio/mpeg",
"server_url": "/radio/jazz",
"stream_start": "humandate",
"stream_start_iso8601": "computerdate",
"title": "author - title",
"dummy": null
},
{
"audio_info": "bitrate=320",
"bitrate": 320,
"genre": "Jazz",
"listener_peak": 2,
"listeners": 1,
"listenurl": "address",
"server_description": "streamdescription",
"server_name": "streamname",
"server_type": "audio/mpeg",
"server_url": "/radio/jazz",
"stream_start": "humandate",
"stream_start_iso8601": "computerdate",
"title": "author - title",
"dummy": null
}
]
}
}
This appears to be the only jQuery code that you want to replace:
jQuery.get("status-json.xsl", {}, function(response) {
$('#currentTrackTitle-js').html(response.icestats.source[number]['title']);
document.title = response.icestats.source[number]['title'];
});
Vanilla JavaScript equivalent to jQuery.get() is fetch. This will read JSON string from file and convert it to a JavaScript object:
fetch("status-json.xsl")
.then(response => {
// parse JSON from 'status-json.xsl' file
return response.json();
})
.then(status => {
// perform your app logic here
});
This jQuery code:
$('#currentTrackTitle-js').html(response.icestats.source[number]['title']);
can be replaced with this vanilla JavaScript:
const currTitle = document.getElementById('currentTrackTitle-js');
currTitle.innerHTML = status[number]['title'];
Putting it all together:
const currTitle = document.getElementById('currentTrackTitle-js');
fetch("status-json.xsl")
.then(response => {
return response.json();
})
.then(status => {
currTitle.innerHTML = status.icestats.source[number]['title'];
document.title = status.icestats.source[number]['title'];
});

click function for 'sort' to rearrange my obj data output in HTML

I am working on a series of 'click functions' that will essentially 'sort' or rearrange the output of my Obj data content, via the data field values, that I have already iterated over into my HTML.
For instance; below I am trying to create a 'sort' function with the 'Size' data field values - so when the click function is fired; the data within my HTML, will rearrange in accordance to smallest to greatest. I am achieving this sort logic, the problem I'm having is; when the sort function is executed the content is not rearranging in HTML. I can verify the logic in the console, but cannot get the HTML output to sort accordingly. Any thoughts?
here is a visual. So clicking the 'Size' header should execute 'sort/rearrange'... by size.
var json =[{
"Name": "zips",
"Type": "Directory",
"DateModified": "6/14/2018 17:22:50",
"Size": "5 KB",
}, {
"Name": "presets",
"Type": "Directory",
"DateModified": "5/11/2018 7:32:10",
"Size": "2 KB",
}, {
"Name": "workflow",
"Type": "Directory",
"DateModified": "6/26/2018 10:29:59",
"Size": "6 KB",
},
];
var string ="";
for (i in json) {
string +='<div class="row"><div class="col-md-15 col-sm-1"><input type="checkbox" name="ck"></div><div class="col-md-15 col-sm-4"><span class="folders">'+json[i].Name+'</span></div><div class="col-md-15 col-sm-3"><span class="directory">'+json[i].Type+'</span></div><div class="col-md-15 col-sm-3"><span class="date-stamp">'+json[i].DateModified+'</span></div><div class="col-md-15 col-sm-1"><span class="date-size">'+json[i].Size+'</span></div></div>';
};
// Just outputs data into bootstrap columns, rows, from Obj data source
document.getElementsByClassName('update-data')[0].innerHTML =string
// Click function to reorganize data accordingly as 'sort' function
document.getElementById('size').addEventListener('click', function () {
json.sort(function(a, b) {
return parseFloat(a.Size) - parseFloat(b.Size);
});
});
The below is the relevant HTML.
<!-- etc -->
<div>
<div class="col-md-15 col-sm-1">
<span id="size">Size</span>
</div>
</div>
<div class="update-data">
<!-- output-->
</div>
I am getting the result in the console.. Just cannot get the outputted HTML to update.
You have already generated the html string using JSON data and inserted it into HTML of the page. Sorting the JSON afterwards will not automatically change the HTML output. What you have to do is, generate and insert new sorted HTML in place of original each time you sort the JSON. Something like this...
document.getElementById('size').addEventListener('click', function () {
json.sort(function(a, b) {
return parseFloat(a.Size) - parseFloat(b.Size);
});
var str ="";
for (i in json) {
str +='<div class="row"><div class="col-md-15 col-sm-1"><input type="checkbox" name="ck"></div><div class="col-md-15 col-sm-4"><span class="folders">'+json[i].Name+'</span></div><div class="col-md-15 col-sm-3"><span class="directory">'+json[i].Type+'</span></div><div class="col-md-15 col-sm-3"><span class="date-stamp">'+json[i].DateModified+'</span></div><div class="col-md-15 col-sm-1"><span class="date-size">'+json[i].Size+'</span></div></div>';
};
document.getElementsByClassName('update-data')[0].innerHTML =str;
});

How to pass $ctrl value from one place to other component

I am using Angular JS (1.6) application. Inside my app I have components -
oprExternalInstructionsApp ->
oprScriptListPanel ->
I have <opr-list> component in my oprScriptListPanel templete file. I am passing $ctrl.externalInstructionsFiltered in <opr-script-list-panel>
Like items="$ctrl.externalInstructionsFiltered"
but I don’t see {{$ctrl.externalInstructionsFiltered}} is having any data inside my templete oprScriptListPanel.
My template code -
<opr-script-list-panel
items="$ctrl.externalInstructionsFiltered"
toolbar-buttons="$ctrl.toolbarButtons"
selected-items="$ctrl.selectedInstructions"
on-search="$ctrl.filterExternalInstructionsChanged(text)"
on-double-click="$ctrl.edit(item)"
item-actions="$ctrl.itemActions"
item-tags="$ctrl.itemTags"></opr-script-list-panel>
in <opr-script-list-panel component I am passing items -
this.externalInstructionsFiltered = [{
"id": "1",
"displayName": "abc",
"description": "aqaa",
"timeout": "3000",
"isEnabled": "false",
"isReadOnly":"false",
"stepId":"ExternalInterface",
"version":"1",
"artifactOrigin":"custom",
"filterId":"qwq" ,
"filterName":"sdsf",
"Script": "abc",
"active": true,
"winner": true,
"icon": "abc"
}];
Component file for opr-script-list-panel
import './oprScriptListPanel.template.html';
var oprScriptListPanelComponent = {
templateUrl: 'oprScriptListPanel.template.html',
bindings: {
toolbarButtons: "<?",
selectedItems: "#?",
onSearch:"&?",
items:"=?",
data:"=ngModel",
oprListDeleteMode:"&?",
onDoubleClick:"&?",
itemActions:"&?",
itemTags:"&?"
}
};
export default oprScriptListPanelComponent;
Template file-
<div>
<opr-toolbar
buttons="$ctrl.toolbarButtons"
selected-items="$ctrl.selectedInstructions"
filter-placeholder="Filter instructions"
on-search="$ctrl.filterExternalInstructionsChanged(text)"
show-first-separator="true">
</opr-toolbar>
</div>
<div class="empty-info" ng-if="$ctrl.externalInstructionsFiltered && !$ctrl.externalInstructionsFiltered.length">
<p ng-bind=":: 'opr.external.instructions.emptyList' | oprL10n"></p>
</div>
{{$ctrl.externalInstructionsFiltered}}
{{$ctrl.selectedInstructions}}
I am not getting any data for {{$ctrl.externalInstructionsFiltered}}, But if I will print {{$ctrl.toolbarButtons"}} I am able to see some array. I checked module reference is correct. I am not getting any error.

Using AngularJS to create a dynamic table - need help going from success/error method to .then() method

I recently asked a question where I was advised to start using AngularJS to dynamically create a table. Unfortunately, I have no knowledge of AngularJS (or coding at all), and was following a tutorial which led to deprecated code. Essentially, from what I can gather, the success and error method used in $http should be replaced with a .then() method. As my code currently stands, all I am being returned is: {{ cribs | json }}.
My html code:
<html>
<head>
<meta charset="utf-8">
<title>ng-cribs Test</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body ng-app="ngCribs" ng-controller="cribsController">
<h1>Testing</h1>
</br>
<div class="well" ng-repeat="crib in cribs">
<h3> {{ crib.name }} </h3>
<p><strong>Contact Number: </strong>{{ crib.contactNumber }}</p>
<p><strong>Email Address: </strong>{{ crib.email }}</p>
<p><strong>Pass Number: </strong>{{ crib.passNumber }}</p>
</div>
<pre>{{ cribs | json }}</pre>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.2.0/ui-bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.2.0/ui-bootstrap-tpls.min.js"></script>
<script src="app.js"></script>
<script src="scripts/cribsController.js"></script>
<script src="scripts/cribsFactory.js"></script>
</html>
My js code (in the same directory):
angular.module('ngCribs', ['ui.bootstrap']);
My AngularJS factory code (in a "scripts" subfolder):
angular
.module('ngCribs')
.factory('cribsFactory', function($http) {
function getCribs() {
return $http.get('data/data.json');
}
return {
getCribs: getCribs
}
});
My AngularJS controller code (also in the "scripts" directory):
angular
.module('ngCribs')
.controller('cribsController', function($scope, cribsFactory){
$scope.cribs;
cribsFactory.getCribs().success(function(data) {
$scope.cribs = data;
}).error(function(error) {
console.log(error);
});
// $scope.hello = 'Hello wo!';
});
And my JSON file (in a separate directory called "data"):
[
{
"name": "Joel Doe",
"dob": "17-03-1994",
"houseNumber": "31",
"postcode": "LS4 2RS",
"contactNumber": "07941405771",
"email": "joeldoe#outlook.com",
"passNumber": "01",
},
{
"name": "Harry Doe",
"dob": "21-04-1992",
"houseNumber": "43",
"postcode": "LS2 1DH",
"contactNumber": "0797651387",
"email": "harrydoe#outlook.com",
"passNumber": "02",
},
{
"name": "Jane Doe",
"dob": "19-12-1993",
"houseNumber": "65",
"postcode": "LS1 6EK",
"contactNumber": "07979804398",
"email": "janedoe#outlook.com",
"passNumber": "03",
},
]
I have also included a link to my code: http://codepen.io/anon/pen/yVyXzp
According to documentation https://docs.angularjs.org/api/ng/service/$http
Code in cribsController should be changed to
cribsFactory.getCribs().then(function(data) {
$scope.cribs = data;
}, function(error) {
console.log(error);
});
You have few more issues with the code, so I refined them as well.
Working code - http://plnkr.co/edit/TM8jYldnE6DCquemSkX7?p=preview
Code-
angular
.module('ngCribs')
.controller('cribsController', function($scope, cribsFactory){
$scope.cribs = {};
cribsFactory.getCribs().then(function(data) {
$scope.cribs = data.data;
}, function(error) {
console.log(error); // Handle the error here
})
})
Things I enhanced to make it working -
Cleaned JSON to validate, please check as it was not valid.
Remove unnecessary <script> tags and HTML elements in index.html.
Added Error handling code for then().
It is a good practice to initialize your scope variable at start no just $scope.cribs.
Let me know in case of any query.

trying to display json data with angularjs ng-repeat not working

I've seen so many ways to do this, but most are pretty old and I want to make sure I'm doing this correctly. Right now, the way I'm using isn't working and I feel like I'm missing something.
I'm getting the JSON back fine, I just need to get it to display in a table after I click the button.
Here is the JSON. This is how I'm going to get it from our server, I can't add any "var JSON =" or add any scope like "$scope.carrier" to the data, unless there's a way to add it after I've fetched the data.
{
"carrier":
[
{
"entity": "carrier",
"id": 1,
"parentEntity": "ORMS",
"value": "Medica"
}, {
"entity": "carrier",
"id": 2,
"parentEntity": "ORMS",
"value": "UHG"
}, {
"entity": "carrier",
"id": 3,
"parentEntity": "ORMS",
"value": "Optum"
}, {
"entity": "carrier",
"id": 4,
"parentEntity": "ORMS",
"value": "Insight"
}, {
"entity": "carrier",
"id": 5,
"parentEntity": "ORMS",
"value": "Insight"
}
]
}
Here is the app.js file to bring back the JSON data:
var app = angular.module('myTestApp', []);
app.controller('myController', ['$scope', '$http', function($scope, $http) {
var url = 'test.json';
$scope.clickButton = function() {
$http.get(url).success(function(data) {
console.log(data);
});
}
}]);
And then of course the HTML:
<div class="col-lg-12 text-center">
<button type=button class="btn btn-primary load" ng-click="clickButton()">Click!</button>
<table class="">
<tbody ng-repeat="carrier in carriers">
<tr>
<td>
<h3 class="">{{ module.entity }}</h3>
<h3 class="">{{ module.id }}</h3>
<h3 class="">{{ module.parentEntity }}</h3>
<h3 class="">{{ module.value }}</h3>
</td>
</tr>
</tbody>
</table>
</div>
I'm also wondering if I can use the ng-grid to put this in a table. I know they just upgraded it to ui grid so I'm not sure if this is still a feasible approach.
Also, I'm not getting errors, the data just won't display in the table right now. All I know is its returning the data properly, just not displaying in the table.
Any help is appreciated.
I looked at your plunker seems like you need to:
add angular script
wire the app and the controller
your variable in the repeater is wrong, I change it
take a look to this fixed plunker:
http://plnkr.co/edit/TAjnUCMOBxQTC6lNJL8j?p=preview
$scope.clickButton = function() {
$http.get(url).success(function(returnValue) {
alert(JSON.stringify(returnValue.carrier));
$scope.carriers = returnValue.carrier;
});
}
You never assign the value of the returned array to $scope.carriers.
At the line where you say console.log(data); add this:
$scope.carriers = data.data;
Here is the updated clickButton function (with a variable name change to reduce confusion):
$scope.clickButton = function() {
$http.get(url).success(function(returnValue) {
$scope.carriers = returnValue.data;
});
};

Categories