Angular external templating vs Handlebars external templating - javascript

this is how I load and compile my templates in Handlebarsjs,
define([
'jquery',
'handlebars'
],
function ($, Handlebars) {
// #reference: http://berzniz.com/post/24743062344/handling-handlebars-js-like-a-pro
Handlebars.getTemplate = function(name) {
if (Handlebars.templates === undefined || Handlebars.templates[name] === undefined) {
$.ajax({
url : 'js/template/' + name + '.handlebars',
success : function(data) {
if (Handlebars.templates === undefined) {
Handlebars.templates = {};
}
Handlebars.templates[name] = Handlebars.compile(data);
},
dataType: "text",
async : false
});
}
return Handlebars.templates[name];
};
// Precompile your templates and add/paste them below here.
});
and I can just retrieve the template with this line below,
this.$el.html(Handlebars.getTemplate('list')({contacts: response}));
So this I don't have to use ajax to call the same template over and over again. I can just get it from the Handlebars' storage.
Is this possible with Angularjs? I have been looking up for tutorials for doing this in Angualrjs but can't find any. Any ideas where is the good start?

Angular.js caches templates when they are requested (so the request only happens once), but you can prepopulate that cache using $templateCache.

Related

Cannot find name 'jQuery' error in controller.js

I am developing a UI5 app in VS Code.
I added a new count function to the *.controller.js file, and in order to display the count from the server, I am using jQuery like in the following code:
jQuery.each(this._mFilters, function (sFilterKey, oFilter) {
oModel.read("/portfolios/$count", {
filters: oFilter,
success: function (oData) {
var sPath = "/" + sFilterKey;
oViewModel.setProperty(sPath, oData);
}
});
});
Unfortunately, I get the following error:
Does anyone know why was the error triggered and how it can be fixed?
Any help or suggestion is much appreciated.
I assume this._mFilters is an object. In that case, try with:
Object.keys(this._mFilters).map(sFilterKey => {
const oFilter = this._mFilters[sFilterKey];
oModel.read("/portfolios/$count", {
filters: [ oFilter ],
success: function(sCount) {
const sPath = `/${sFilterKey}`;
oViewModel.setProperty(sPath, +sCount);
},
});
});
Also the parameter filters awaits an array instead of a single Filter instance.
If jQuery is still preferred, include "sap/ui/thirdparty/jquery" (formerly "jquery.sap.global") to the dependency list of the controller.
sap.ui.define([
"sap/ui/core/mvc/Controller",
// ...,
"sap/ui/thirdparty/jquery",
], function(Controller,/*...,*/ jQuery) {
// jQuery is here available
});

Load Angular 5 component after gapi has been loaded

I am writting an angular 5 app using the CLI.
I am using gapi to retrieve user data in order to populate a form.
The client script is included in the index.html file :
<head>
<meta charset="utf-8">
<script src="https://apis.google.com/js/client.js"></script>
...
</head>
Here is my component with the call :
userProfileModel: UserProfileModel = new UserProfileModel();
ngOnInit() {
this.form = this.toFormGroup();
this.onFormChanges();
this.userService
.getUserById(this.userId)
.then(usr => {
this.mapModel(usr.result['profile']);
})
.then(() => {
this.form.patchValue(this.userProfileModel);
});
}
And the userService's method :
declare var gapi: any;
export class UserService {
getUserById(id: number) {
return gapi.client.request({
method: 'GET',
'path': this.constants['endpoint_user_getbyid'] + '/' + id,
'root': this.constants['api_url']
});
}
...
}
Problem is, gapi seems to do not be initialized right after my component has finished loading : I have to set a >500ms timeout to be able to use it, and it's ugly.
This code gives me the following error :
ERROR TypeError: Cannot read property 'request' of undefined
Please not :
1- I haven't installed anything with npm / yarn, I am simply using the script with the gapi var declaration.
2 - after every build, the code works without any error and populates my form the first time the page is loaded, then after one refresh, it fails everytime.
How can I tell angular to load client.js at startup before all the components ?
Thanks !
Thanks to #ADarnal I finally found a solution by reading this topic :
How to pass parameters rendered from backend to angular2 bootstrap method
I followed the same exact process described in computeiro's answer.
My equivalent of the "BackendRequestClass" class is a GapiService.
In this Gapi service, the load method allows me to load gapi before any other call is executed :
/* GapiService */
loadGapi() {
return new Promise((resolve, reject) => {
gapi.load('client', () => {
gapi.client.init({apiKey: 'AIzaSyD5Gl9...'}).then(() => {
resolve(gapi.client);
})
});
});
}
// Method used in any component
getUserById(id: number) {
return gapi.client.request({
method: 'GET',
'path': this.constants['endpoint_user_getbyid'] + '/' + id,
'root': this.constants['api_url']
});
}
Finally; in my component, i inject this gapiService and I am able to use client.request on component init !
ngOnInit() {
this.gapiService
.getUserById(5066549580791808)
.then(
...
});

RequireJS - Issues properly loading ko.editables.js

Im new to requirejs and loving it so far. I have it working juste fine with knockout js. I then introduced a plugins called ko.editables (https://github.com/romanych/ko.editables) that would allow to undo changes very easily.
I added the path on in my equirejs config file so that ko.editables has knockout as it's dependency. In my knockout application code I defined knockout and then ko.editables and the files (knockout.js and ko.editables.js) are loading correctly from what I can see in my crome console sources.
Here is my requirejs config file:
require.config({
baseUrl: './js',
paths: {
"ko_editables": "ko.editables"
},
"shim": {
ko_editables: {
deps : [ 'knockout' ]
}
}
});
This is my application code I have that controls my knockout view model.
define(["knockout", "ko_editables"], function(ko, editables) {
... I hide some code here just to show the ko.editable functions im using.
self.Edit = function (incident) {
var CurrentEdititngIncident = self.EditingIncident();
if (CurrentEdititngIncident && CurrentEdititngIncident != incident) {
if (CurrentEdititngIncident.hasChanges()) {
if (confirm('Your have unsaved changes. Press Ok to cancel these changes. Press Cancel to continue editing')) {
CurrentEdititngIncident.rollback();
} else {
return;
}
};
}
ko.editable(incident);
incident.beginEdit();
self.EditingIncident(incident);
self.showDialog(true);
};
self.SaveorUpdate = function (incident) {
var id = this.ID,
self.EditingIncident().commit();
url = Incident.BASE_URL + (id ? '(' + encodeURIComponent(id) + ')' : '');
return $.ajax(url, {
type: id ? "MERGE" : "POST",
data: ko.toJSON({
Description: this.Description,
Incident: this.Incident
}),
processData: false,
contentType: "application/json;odata=verbose",
headers: id ? Incident.UPDATE_HEADERS : Incident.CREATE_HEADERS,
success: function (incident) {
self.showDialog(false);
self.EditingIncident(undefined);
console.log("Record was sucessfully saved.");
}
});
... I hide some code here just to show the ko.editable functions im using.
};
I created a version without requirejs in a jsfiddle to demonstrate that the same code works without requirejs. So im not quite sure what ut us that im missing. I went trough the website https://github.com/romanych/ko.editables and it mentions that its AMD compatible but cant find info on how to properly load it.
Hoping that some people are familiar with requirejs or with ko.editables. Would anyone have any ideas?

Passing variable data between classes OO Javascript

I am trying to create a basic app for creating and editing contact details - for the purposes of improving my JavaScript skills. For some reason I can't manage to pass variable data from one class to the next - I'm trying to implement something similar to an MVC just to get started before i move to backbone.js
Here's my code:
//App Model Class
var contactsAppModel =
{
contacts:contacts,
/* App Methods */
init: function()
{
var theDetails;
//initiate App - pull App data
$j.ajax({
type: "post",
url: "inc/contactsModel.php",
dataType: "html",
data: '',
beforeSend: function(url,data)
{
$j('#result').html('<img src="images/page-loader.gif" height="80px" width="80px">').fadeIn('slow');
},
success: function(data)
{
this.contacts = data;
return this.contacts;
}
});
//alert('From WithOut '+this.contacts);
}
};
//App Class
var contactsApp =
{
//App Properties
contactDetails:'',
/* App Methods */
init: function()
{
//populate App properties
this.contactDetails = contactsAppModel.contacts;
$j('#result').html('<p>Contact Details:</p>'+this.contactDetails).css({'border-color': 'red'}).fadeIn('slow');
alert('From contactsApp: '+this.contactDetails);
},
};
How can i access the contents of variable 'data' from the contactsAppModel inside of contactsApp class? I'm trying to implement and OO-based solution to running a Javascript powered App with AJAX - not a functional approach.
Maybe can put contactsAppModel.init(); on the first line of your contactsApp.init() method.

using variables in i18n resource files

Hello everyone,
I'm using the i18n (for require.js) library to load my translated strings from resource files based on the user's language.
I have used this approach, since I'm using both backbone and require.js in my project. But I'd like also to put an argument/variable to the string stored in the i18n resource file.
Let's say this is the i18n resource file
define({
'root': {
'options': {
'test': 'Yellow {variable.x}'
}
},
"en-us": true
});
now I'm not really sure whether it's possible possible to pass an argument to evaluate the variable inside the resource file.
define(['underscore', 'backbone', 'models/model', 'templates/template' , 'i18n!nls/resource'], function ( _, Backbone, tModel, template, resource) {
var TooltipView = Backbone.View.extend({
el : $('#test'),
initialize: function(options){
this.model = new tModel();
},
render: function(){
var $el = this.$el;
if(template.length != 0){
var compiledTemplate = template['test']( resource, { variable: "14"} ) /// loads pre-compiled template ///
$el.html(compiledTemplate);
}else{
console.log(" [e] No template found. ");
}
});
}
});
return TooltipView;
});
I'd like to achieve this output:
<h1> Yellow 14 </h1>
As #Evgeniy suggested , I should have used the sprintf library for this case.
Solution:
template:
<span> <%= sprintf( data.text, data.id ) %> </span>
resource file:
define({
'root': {
'options': {
'test': 'Yellow %i'
}
},
"en-us": true
});
then in view I needed to change this:
define(['underscore', 'backbone', 'models/model', 'templates/template' , 'i18n!nls/resource', 'sprintf'], function ( _, Backbone, tModel, template, resource, s_utils) {
...
..
var data = _.extend( resource, { id: 11 } , s_utils ); // this enabled me to use the sprintf function in my template file.
var compiledTemplate = template['test']( data ) /// loads pre-compiled template ///
$el.html(compiledTemplate);
..
return TooltipView;
});

Categories