i i have a kendo UI panelBar, and i want to load data dynamically. I want inside panelBar option to have a template that use Angular. I have this part of code but this doesnt work.
$http({
method: 'GET',
url: '/PDFEditor/GetPDFDocumentInfo',
params: { fileId: fileId }
}).then(function successCallback(response) {
$scope.test = "My name is: <h1>Bond, James Bond </h1>";
var tml = '<div id="testId"></div>';
$scope.pdfInfo = response.data;
$scope.appendToPanelBar([{
text: 'Info',
content: tml
}]);
document.getElementById("testId").innerHTML = "<p ng-bind-html=\"test\"></p> {{test}}";
}, function errorCallback(response) {
//todo
console.error('todo error handling');
});
I also tried without to get element by id and add directly to content: '{{test}}'. Seems that AngularJS doesn't compile this template.
I find the solution!!
$scope.test = "My name is: <h1>Bond, James Bond </h1>";
var tml = '<div id="testId"></div>';
var data = $compile('<p>{{test}}</p>')($scope);
console.log(data)
$scope.pdfInfo = response.data;
$scope.appendToPanelBar([{
text: 'Info',
content: tml
}]);
document.getElementById("testId").append(data[0]);
cheers!
Related
I've been creating a number of small directives and using hard-coded arrays for testing while I build out functionality. Now that I've got some of that done, I went back and created a service to load the data from a website via JSON; it returns a promise and when it's successful I update the property my template is based off of. Of course, as soon as I did that my directive stopped rendering correctly.
What is the preferred way of binding my directive to asynchronously loaded data so that when the data finally comes back my directive renders?
I'm using Angular 1.4.7.
Here's a simple example of my hard-coded version.
angular
.module('app', []);
angular.module('app').controller('test', function(){
var vm = this;
vm.inv = 'B';
vm.displayInv = function () {
alert('inv:' + vm.inv);
};
});
angular.module('app')
.directive('inventorytest', function () {
return {
restrict: 'E',
template: '<select ng-model="ctrl.selectedOption" ng-options="inv.code as inv.desc for inv in ctrl.invTypes"></select>{{ctrl.sample}}. Selected: {{ctrl.selectedOption}}',
scope: { selectedOption: '='},
bindToController: true,
controller: function () {
this.invTypes = [
{ code: 'A', desc: 'Alpha' },
{ code: 'B', desc: 'Bravo' },
{ code: 'C', desc: 'Charlie' },
];
this.sample = 'Hello';
},
controllerAs: 'ctrl'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script>
<div ng-app="app" ng-controller="test as vm">
<inventorytest selected-option='vm.inv'></inventorytest>
<br/>
Controller: {{vm.inv}}
</div>
My service is essentially just a thin wrapper around an $http call, ex:
return $http({ method: 'GET', url: 'https://myurl.com/getinfo' });
And I had tried modifying my code to do something like:
this.invTypes = [ { code: '', desc: '' }];
ctrService.getInfo()
.then(function successCallback(response) {
this.invTypes = response.data;
}, function errorCallback(response) {
// display error
});
Like I said, that doesn't work since it seems Angular isn't watching this property.
Within the callback this has a different context and isn't what you want it to be.
You need to save a reference to the controller this and use that within any callbacks
// store reference to `this`
var vm = this;
vm.invTypes = [ { code: '', desc: '' }];
ctrService.getInfo()
.then(function successCallback(response) {
// must use reference to maintain context
vm.invTypes = response.data;
}, function errorCallback(response) {
// display error
});
I already did some research about this issue, but I don't find any problems in the code. If I save the file to disk it looks fine.
The document could not be loaded...
The javascript blob object has bytes.
Response code is 200.
Maybe somebody finds a coding issue?
The html:
<div data-ng-show="vouchercontent">
<embed ng-src="{{vouchercontent}}" style="width:400px;height:700px;"></embed>
</div>
Angular Controller:
$scope.vouchercontent = undefined;
$scope.generateVoucher = function() {
var self = this;
generateVoucherService.generateVoucher($scope.voucherdata).then(function(result) {
var file = new Blob([result], {type: 'application/pdf' });
var fileURL = window.URL.createObjectURL(file);
$scope.vouchercontent = $sce.trustAsResourceUrl(fileURL);
}, function(error) {
alert(error);
});};
Angular Service:
generateVoucher : function(data){
return $http.post('rest/generatevoucher/generate', data, {responseType: 'arraybuffer'})
.then(function(response){
return response.data;
}, function (response) {
return $q.reject(response.data);
});
}
Response in the service:
Response in the controller:
I need to write directive to append html in div
Here i want to append html which i get it from server usinh $http post request
<div id="invoice_template_preview"
ng-bind-html-unsafe="invoice_html_template"
class="span6"
style="background: rgba(242, 230, 205, 0.95);margin: -100px 0 0 0;border: 1px solid #ddd; height: auto;padding: 18px;position: relative;width: 50% !important;">
</div>
This is my angular function to get html from db
$scope.getInvoiceTemplate = function() {
$scope.invoiceTemplate = [];
var request = $http({
method: "post",
url: "/c_make_invoice/",
data: {
action: 'getInvoiceTemplate',
id:$scope.our_company_id
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
request.success(function (data) {
$scope.invoiceTemplate = data.result;
$scope.invoice_html_template = $scope.invoiceTemplate.invoice_html_template;
$scope.invoice_num_format = $scope.invoiceTemplate.invoice_num_format;
});
};
I try this
$scope.invoice_html_template = $scope.invoiceTemplate.invoice_html_template;
but its not a proper way to solve this.
I return json from server, how i can append that html in #invoice_template_preview
Updated directive to watch the scope variable. When it changes the template html is changed to whatever is in the variable.
.directive('CustomDirective', function(){
return {
restrict: 'E',
link: function(scope, element, attrs){
scope.$watch('invoice_html_template', function(){
var template = scope.invoice_html_template;
element.html(template);
$compile(element.contents())(scope);
});
},
template: '<div>{{$scope.invoiceTemplate}}</div>'
});
and it can be used:
<div id="invoice_template_preview">
<custom-directive></custom-directive>
</div>
You should also be using $sce when getting hold of the HTML. see sce
request.success(function (data) {
$scope.invoiceTemplate = $sce.trustAsHtml(data.result.invoice_html_template);
Whan i try $compile I get that $compile is not defined, I fixed that whan I add $compile param in controller initialization.
After that I simple add this code
$('#invoice_template_preview').html($compile($scope.invoiceTemplate.invoice_html_template)($scope));
I have an Angular JS app that is communicating with a REST API. The app has an admin part that let a user create, read, update and delete a resource.
There's several different resources, one partial per resource where I define each member as an input field of some sort. I have created a directive that creates a two way binding for whats common for the templates.
I have also created a ngResource for each of my resources.
Now to my problem. I have the controller for one resource working, and it mostly contains just functions that are called directly from the partials (e.g submit() ), and communicates with the ngResource.
The code itself can, with a few exceptions, be copied to all of the other controllers and just change the resource name. This is what I want to avoid.
How can I create an abstract ParentCtrl and somehow inject the resource I need at that time?
Is this testable? Is this a bad approach of the problem?
Normally I would have tried to abstract a model instead of a controller, but I can't really see how in this case.
Edit: Added code
Resource:
angular.module('experienceServices', ['ngResource'])
.factory('Experience', function($resource){
return $resource('/api/experience/:id',
{'id': '#_id'}, {edit: { method: 'PUT' }});
});
Controller:
App.controller('ExperienceCtrl', function( $scope, Experience ) {
$scope.resources = [];
$scope.currentItem = {};
$scope.updateResources = function(){
$scope.resources = Experience.query();
};
$scope.findById = function(id){
for (var i = 0; i < $scope.resources.length; i++){
if ($scope.resources[i]._id === id){
return $scope.resources[i];
}
}
};
$scope.showItem = function(id){
$scope.currentItem = findById(id);
};
$scope.create = function (experience){
Experience.save(angular.copy(experience), function(){
$scope.updateResources();
});
};
$scope.editItem = function (experience){
var item = angular.copy(experience);
if (!item.hasOwnProperty('_id')){
alert('Can not modify non existing item');
}
Experience.edit(item, function(res){
$scope.updateResources();
});
};
$scope.edit = function(id){
$scope.experience = $scope.findById(id);
};
$scope.del = function(id){
Experience.remove({ id: id }, function(){
$scope.updateResources();
});
};
$scope.updateResources();
});
Directive:
App.directive('resources', function (){
return {
scope: {
list: '=',
display: '#',
edit: '&',
del: '&'
},
template: '<div ng-repeat="elem in list">Name: {{ elem[display] }}' +
' <button ng-click="edit({ item: elem._id })">Edit</button> ' +
' <button ng-click="del({ item: elem._id })">Delete</button> ' +
'</div>'
};
});
what about wrapping your entire API to a service and accessing it from the controllers ? you can pass the resource type as an argument to the functions
My code is as follow:
var AppRouter = Backbone.Router.extend({
_data: null,
_length: 0,
_index: null,
_todos: null,
routes: {
"*action": "index",
"category/:name": "hashcategory"
},
initialize: function(options){
this._data = options.data;
this._todos = new TodosCollection(options.data);
this._length = this._todos.length;
this._index = new CategoriesView({collection: this._todos});
},
index: function(){
this._index.render();
},
hashcategory: function(name){
console.log('started');
}
});
initializeRouter = function (router) {
Backbone.history.start({ pushState: true });
$(document).on('click', 'a:not([data-bypass])', function (evt) {
var href = $(this).attr('href');
var protocol = this.protocol + '//';
if (href.slice(protocol.length) !== protocol) {
evt.preventDefault();
router.navigate(href, true);
}
});
return router;
};
var start = function(){
p = $.ajax({
url: 'data/todolist.json',
dataType: 'json',
data: {},
success: function(data) {
var approuter = initializeRouter(new AppRouter({data: data}));
}
});
};
I have a <a> link in my html which has a href = "category/num1" attibute. But every time I click the link, it always shows a security error in firebug. Actually I just have one index.html page, what I want to do is append a string to it to make a fake html page like folder/index.html/category/num1 and all of the things will still be rendered in current page. But the url shown to me when the link is hovered is folder/category/num1. Because this path actually doesn't exist in my folder, I think that's why it shows a security error.
So how should I fix it? Should I create another html page and the corresponding folder? Or can I make all of the routing in one index.html page?
Try putting a # in the href, like
href = "#category/num1"