angular ngFor call javascript - javascript

I having HTML code like this
<div class="owl-carousel owl-theme owl-loaded">
<div class="owl-stage-outer">
<div class="owl-stage" *ngFor="let product of products; let i=index;">
<div class="owl-item">
<carouselFixture [stream]="product.stream" *ngIf="product.viewModelType == 'ProductSummary'" ></carouselFixture>
</div>
</div>
</div>
This is working fine. The problem I face is when the new product is added immediately it has to be shown in the owl carousel... actually it is loading but wrongly as shown in the image below
So to solve the problem we need to call the below add function in ngFor
$('#add').on('click', function () {
var html = '<div class=\"item\"><carouselFixture
[stream]="product.stream" *ngIf="product.viewModelType ==
'ProductSummary'" ></carouselFixture></div>';
console.log(html);
owl.trigger('add.owl.carousel', [html, 0])
.trigger('refresh.owl.carousel');
});
Can anyone tell me how to call this 'add' function...

AngularDart doesn't allow for dynamic components to be added to the page using pure html like that. This is for security, and performance reasons. It doesn't actually put the full angular engine in the page at runtime.
It does have other ways of doing this tho. The easiest is to add another entry onto the list and it will be displayed in the for loop.
The other possibility is to use the ComponentFactory to add it to the page https://webdev.dartlang.org/api/angular/angular/ComponentFactory-class
I'm not sure what owl is doing exactly in its call, but you could add the html without the angular component and use the component factory to insert it in the right place after owl does it's thing.

Related

Angular directives inside InnerHTML

I know its not possible to inject angular directive along html code inside inner html, is there any work around it? I'm trying to read the html and the directive from a html file and inject it inside a div, I thought about using component factory and create the component dynamically but the directive in the html file can be anywhere in the code not sure how I can append it to the right place in dom, I don't have much experience working with component factory so please let me know if there is a way.
ngOnInit(): void {
let loading = this.loadingService.addTask();
this.route.paramMap
.take(1)
.subscribe(params => {
let page: string = params.get("page") || "";
if (page) {
this.trainingService.getPageContent(page)
.take(1)
.subscribe(res => {
this.content = res;
this.loadingService.completeTask(loading);
})
}
else {
this.loadingService.completeTask(loading);
}
},
error => {
this.notificationService.error("Error retrieving training page", error);
this.loadingService.clearAllTasks();
})
here is my template
<div [innerHtml]="content"></div>
here is an html page example that should be injected (this is an external html page file)
<div class="row">
<div class="col-md-12">
<div class="panel panel-default b">
<div class="panel-body">
<div class="row">
<!--the directive-->
<sa-azure-media-player [source]="the link"></ss-azure-media-player>
</div>
</div>
</div>
</div>
</div>
There isn't a way to do this. The workaround would be to change the way you inject html. Instead of injecting as html, write a sub-component, give it the right info (as an [json-]object!), and off you go.
In case you do not have control of the incoming info (in your case html), you are forced to mould it into an object, so you can use it in angular.
In a recent project I had to have text content that might contain iframes (iframes don't work well in angular). The solution was to parse and save the content in the backend as a JSON-object containing text- and iframe-parts in the right order (that cost some time, unfortunately). Once I got hold of it in Angular, I could inject the texts and iframes of the JSON-object by using typescript. And, of course, do the right thing for the right element.
So, in case you have control over the incoming info (be it html or whatever kind of identifiable object), that's where you should change the procedure (and make full use of the angular MVC-stuff). In case you do not have control over that, please provide some more details as to what needs to be done and what the cicumstances are.

Angular 1.5.5 render html based on return value of an $http call

I want to know the best way to proceed given the following information:
I have a controller which makes 2 http calls using a factory.
DataFactory.getTestDisplaySections(testID).then(function (response) {
$scope.testSections = JSON.parse(response.data);
});
DataFactory.getTestObjectByTestID(testID).then(function (response) {
$scope.testObject = JSON.parse(response.data);
});
The call returns two arrays. I want to generate html with data from the array embedded in it. Right now, my template for the controller contains only an empty shell of a page.
<div class="container">
<div class="row">
<div ng-bind-html="sectionHTML"></div>
</div>
</div>
The sectionHTML above is my variable which contains the html markup for the entire page.
The first call returns data that gives me names of panels that are to be displayed on the page. These could be 4 or more. I want to use the following html to display each panel.
$scope.sectionHTML = '<div class="col-lg-6">'+
'<div class="panel panel-primary">'+
'<div class="panel-heading lead">' + panelDiaplayName + '</div>' +
'<div class="panel-body">'+
'<div id="test_info" class="col-lg-12">' +
'</div>'+
'</div>'+
'</div>'+
'</div>'
Should I just go through the panel data in a for loop and create the html that way for each panel?
When I try to add the panelDisplayName using {{}} It shows up as just {{panelDisplayName}} will this be an issue, every time I have to evaluate an angular expression? How can I resolve this issue?
Second, I have other information that I need to display within each of the panels. This comes from the second http call. Each panel will have details in it and each piece of information will be editable. Can anybody help with the best way to do it?
I can give more explanation if anyone needs it.
Thanks
Paras
I think you are asking about multiple issues here, so I will try to help solve the first two, looping through your array to build your page and helping you get the {{}} data-binding to work.
For your panels, don't use a for loop and build html in your controller. You are using angular, the angular way is using ng-repeat. You add this to your html template and it will build the dom by iterating over your array. In your example:
.html
<div class="container">
<div class="row">
<!-- this is where we are iterating over the array (ng-repeat) -->
<div class="col-lg-6" ng-repeat="section in testSections">
<div class="panel panel-primary">
<!-- section is the current item being iterated in the array, so we are printing the displayName for the section -->
<div class="panel-heading lead">{{section.panelDiaplayName}}</div>
<div class="panel-body">
<div id="test_info" class="col-lg-12">
</div>
</div>
</div>
</div>
</div>
</div>
As for the data-binding. My assumption here is that you aren't adding ng-app and/or ng-controller to elements that encompass your data-bindings. For example:
.html
<body ng-app="yourApp" ng-controller="yourController">
<h1>{{testMessage}}</h1>
</body>
app.js
var app = angular.module('yourApp').controller('yourController', ['$scope', function($scope) {
$scope.testMessage = "Hello World";
}])
As for your second question about dealing with data that will be edited, I recommend giving that a shot yourself. Look in to angular forms and ng-model. Those should help you get started. After giving that a shot, if you are still struggling, ask a new question for the specific issue you are struggling with.

Override a components template in Angular2/4?

If I detail the problem I'm trying to solve, it will help with my question.
I want to use HTML in the Angular Material tooltip, the current template doesn't enable this functionality:
<div class="mat-tooltip"
[ngClass]="tooltipClass"
[style.transform-origin]="_transformOrigin"
[#state]="_visibility"
(#state.done)="_afterVisibilityAnimation($event)">
{{message}}
</div>
In order to use HTML in the tooltip I'd like to override the template to the following:
<div class="mat-tooltip"
[ngClass]="tooltipClass"
[innerHTML]="message"
[style.transform-origin]="_transformOrigin"
[#state]="_visibility"
(#state.done)="_afterVisibilityAnimation($event)">
</div>
Is this possible? Is there another method I'm overlooking to achieve what I'm looking for?
The html file cannot be changed, however you can access the element from the component.ts file
#ViewChild('dataContainer') dataContainer: ElementRef;
loadData(data) {
this.dataContainer.nativeElement.innerHTML = data;
}
as found in thie SO-answer.

AngularJS Ng-repeat, create dynamic dom with expressions

Here is The problem i am trying solve. I would like to create a JS script that uses angular to dynamically create div elements while adding an additional expression eg {{levelone}}.
Here is an an example of what i am expecting the output to be if i know i have 5 iterations of Dom elements.
<div ng-switch-when="0">{{levelZero}}</div>
<div ng-switch-when="1">{{levelOneA}}{{levelOneB}}</div>
<div ng-switch-when="2">{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
etc.....
So as you can see i am adding an expression on each time. I just dont know how i can keep adding them on via a repeat loop and then get them to compile correctly with AngularJS. I am trying to make my DOM as Dynamic as possible.
EDIT
Every time i loop 1 more i am adding an expression ->{{expression}} to the div with JS or angular. I am not hard coding the expression into each div as each div is also dynamically created. But with a twist i am adding that extra expression ie 3 expressions from the previous div and adding one more expression making four. see example below.
<div ng-switch-when="3"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
This one below is dynamically generated
<div ng-switch-when="4"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}{{THIS EXPRESSION IS GENERATED IN js AND ADDED & COMPILED}}</div>
The DOM will be dynamic as long as your data bindings are. I need more info (data model, expectations) to be more accurate but if you set up your data and bind it correctly, it should work. for example if your data looked like this
var data = {
"levelOne" : {},
"levelTwo" : {
"elements" : ["<span id="firstEl"></span>, ...]
},
"levelThree" : {
"elements" : ["<span id="firstEl"></span>, <span id="secondEl"></span>, ...]
}
Then in your template do what #paulgoblin suggested.
}
You could ng-repeat within each switch case. Eg.
<div ng-switch-when="0">
<span>{{levelZero}}</span>
</div>
<div ng-switch-when="1">
<span ng-repeat="expression in levelOne">{{expression}}</span>
</div>
<div ng-switch-when="2">
<span ng-repeat="expression in levelTwo">{{expression}}</span>
</div>
You might want do this with scope function.
<div ng-switch="assignment.id">
<div ng-switch-when="1">{{ getExpressions(assignment.id) }}</div>
<div ng-switch-when="2">{{ getExpressions(assignment.id) }}</div>
</div>

knockout - set visible only one item in a list generated by json

hi it's a cordova app that use devexpress framework based on knockout i need to set visible only one item in a list
the item should correspond to the param.id or this
id_agenzia:ko.observable(params.id),
i've tryed with jquery (setting the id "#"+$data.id_agenzia visible if == id_agenzia ) but if i integrate it doesn't work
the goal is to do something like this
if i put this line it ignores
how is the right way to set visible only the div that corresponds to $data.id_agenzia is valid for $data.id_agenzia==id_agenzia ?
thank you for help
this is the js code with jsfiddle code added
self.selected_id_agenzia = ko.observable('two');
self.jsonLista = ko.observableArray([
{id_agenzia:ko.observable('one'), nome:'N1'},
{id_agenzia:ko.observable('two'), nome:'N2'}
noDataLabel: noDataLabel,
this is the html code with jsfiddle code added
<div class="list-indentation" data-bind="foreach:jsonLista" style="padding-bottom:60px;">
<div id="$data.id_agenzia" data-bind="visible: id_agenzia()==selected_id_agenzia()">
<div class="agency-description-box" >
<span data-bind="text: $data.id_agenzia" class="agency-name"></span>
<span data-bind="text: $data.nome" class="agency-name"></span>
</div>
</div>
</div>
I think I misunderstood what you were doing with the variables. I have made a simplified fiddle to do what I think you want. To make it work:
I assumed a dxList was more or less like a foreach
I changed the name of the outer id_agenzia to selected_id_agenzia, as I was not able to get the comparison to work using $data and $root to distinguish them
I made both items ko.observables, and used the function call on each in the comparison
</div>
The code is all at the fiddle:
http://jsfiddle.net/3ktq4b9s/

Categories