Angular bootstrap HTML processing of tab dynamic content - html

I'm using Angular Bootstrap tabs. I'd like to use them with their content loaded from an Angular Model. However, all HTML in the content loaded fromt eh model is ignored. i.e. if I have
$scope.tabs = [
{ title:'Dynamic Title 1', content:"<b>Dynamic</b> content 1" },
{ title:'Dynamic Title 2', content:'Dynamic content 2', disabled: true }
];
The first tab's content is "Dynamic content 1", not "Dynamic content 1" with "Dynamic" in bold. If the content as statically supplied in the html file, it would show correctly.
Plunker to demonstrate the problem
Anyone know how I can force the html to be parsed properly?
Thank you,
Greg

Based in the comments, you can create a function called:
scope.trustHtml = function(content){
return $sce.trustAsHtml( content );
}
and then change your HTML to be like:
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
<span ng-bind-html="trustHtml(tab.content)"></span>
</tab>

Related

Correct classes not attaching to angularjs accordion and HTML not rendering correctly

I'm trying to implement something like:
http://embed.plnkr.co/3y0Rq1/
The plumbing is all connected, the groups are getting output, and each group is getting the class ng-scope, but my HTML isn't getting the class accordion-group. It's getting ng-binding instead. Also, my HTML is getting rendered as <accordion-group> and <accordion-heading> instead of as <div>s. I think that's key, but I don't know why it's happening. The application to which I'm adding the accordion already appears to have the correct file references, although the versions are newer than in the example at the link I provided. The end result is that the HTML that is rendered is just text. It's not formatted correctly and doesn't expand and contract like an accordion. Here's my code.
References in Index.cshtml (the app is being launched from ASP.NET MVC):
maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
~/Content/dist/css/app.css
code.jquery.com/jquery-2.2.4.min.js
maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js
ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js
ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular-route.js
ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular-cookies.min.js
cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.5.7/angular-sanitize.min.js
Scripts/angular-sortable-view.js
~/Scripts/angular-auto-focus.js
Scripts/ui-bootstrap-custom-tpls-2.0.1.min.js
~/Content/dist/js/app.min.js
~/Scripts/angular-img-http-src.js
Accordion.js
(function (angular) {
angular.module("profilebuilder")
.controller("Accordion",
[
"$scope", function($scope) {
$scope.groups = [
{
title: "Dynamic Group Header - 1",
content: "Dynamic Group Body - 1",
open: false
},
{
title: "Dynamic Group Header - 2",
content: "Dynamic Group Body - 2",
open: false
}
];
}
]);
}(angular));
HTML:
<div class="SearchCriteria" ng-controller="Accordion">
<accordion>
<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
<accordion-heading>
{{group.title}}
</accordion-heading>
{{group.content}}
</accordion-group>
</accordion>
</div>
Correct HTML:
Incorrect HTML:
The problem is the version you are using of the ui.bootstrap
this html will work
<uib-accordion close-others="oneAtATime">
<div uib-accordion-group class="panel-default" heading="{{group.title}}" ng-repeat="group in groups">
{{group.content}}
</div>
</uib-accordion>
Here is the link to a plknr wit example

Component Templating

I'm an angular novice, currently building an angular2 app.
What I want to do is generate a series of DOM components from the following object data:
// Class construct with alphabeticalized properties
export class Screens {
screens: Array<Object>;
}
export var screenData: Screens = {
// Lists all of the audio files in the course
screens: [
{
id: 0,
template: 'templateURL-0.html',
css: 'templateURL-0.css'
},
{
id: 1,
template: 'templateURL-1.html',
css: 'templateURL-1.css'
},
{
id: 2,
template: 'templateURL-0.html',
css: 'templateURL-0.css'
}
]
};
I want the end result to be something similar to the following where template 0 will be displayed twice, and template 1 once; in order:
<app-screen></app-screen> <!-- templateURL-0.html content -->
<app-screen></app-screen> <!-- templateURL-1.html content -->
<app-screen></app-screen> <!-- templateURL-0.html content -->
I read the tutorial on Structural Directives and I think I need to implement something along those lines, however I'm honestly feeling a little lost on the best approach.
Ideally I would like to have something like:
<app-screen *ngFor="let screen of screenData.screens"></app-screen>
Which would then somehow set the template URL depending on what screenData.screens.template is.
Or should I do something like this? (unsure if correct syntax)
<div *ngFor="let screen of screenData.screens" [ngSwitch]="screenData.screens.template">
<app-screen-template1 [ngSwitchCase]="'templateURL-0.html'"></app-screen-template1>
<app-screen-template2 [ngSwitchCase]="'templateURL-1.html'">Ready</app-screen-template2>
</div>
Note: I will never change the templateURL reference.
I found that the best method to achieve this is to implement routing with the built in RouterModule.
So in the end I have the following in my class, where the template property is a url path / url segment.
// Class construct with alphabeticalized properties
export class Screens {
screens: Array<Object>;
}
export var screenData: Screens = {
// Lists all of the audio files in the course
screens: [
{
id: 0,
template: 'template/template-0'
}
]
};
Then when I want to load / instantiate this template, all I have to do is navigate to this url using something like:
<!-- Goes to localhost:4200/template/template-0 -->
<button [routerLink]="[screen.template]"></button>
Where screenis a bound variable in my .ts.
More on routing and navigation here.

Reusing pages in WinJS's Pivot

I'm developing app for Windows Phone 8.1 using WinJS and I used Visual Studio's template for pivot application. My Applications queries external API and displays results in PivotItem. Since there are three very similar queries that reurn same type of data, I'd like to reuse one code for all the sections in Pivot. The PivotItem page consist basically only of ListView with items received from API. My section page javascript looks like this:
var ControlConstructor = WinJS.UI.Pages.define("/pages/bookmarks/sectionPage.html", {
ready: function(element, options) {
//Here I call API based on received option and render the page
}
}
WinJS.Namespace.define("bookmarksApps_SectionControls", {
SectionControl: ControlConstructor
});
My page declaring the Pivot looks like this:
<div class="bookmarks" data-win-control="WinJS.UI.Pivot" data-win-res="{ winControl: {'title': 'BookmarksTitle'} }">
<div class="section1 section" data-win-control="WinJS.UI.PivotItem" data-win-options="{ isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'BookmarksNew'} }">
<div class="sectioncontrol" id="section1contenthost" data-win-control="bookmarksApps_SectionControls.SectionControl" data-win-options="{'section': 'new'}"></div>
</div>
<div class="section2 section" data-win-control="WinJS.UI.PivotItem" data-win-options="{ isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'BookmarksAll'} }">
<div class="sectioncontrol" id="section2contenthost" data-win-control="bookmarksApps_SectionControls.SectionControl" data-win-options="{'section': 'all'}"></div>
</div>
<div class="section3 section" data-win-control="WinJS.UI.PivotItem" data-win-options="{ isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'BookmarksHistory'} }">
<div class="sectioncontrol" id="section3contenthost" data-win-control="bookmarksApps_SectionControls.SectionControl" data-win-options="{'section': 'history'}"></div>
</div>
</div>
Now, when I open the app,pivot page correctly loads and displays first section with data. But when I swipe the different section, new data is loaded (so the ready function is called, but nothing is displayed (page is blank, only PivotItems' headers are visible). But if I swipe back to section1, it contains data, that I want to display in section2.
Is it possible to reuse my SectionPage.html and SectionPage.js in different PivotItems, preferably without too much of boilerplate code?
You need to create custom HTML control which will host these pages, custom control can accept uri as data-win-options, then inside your control you can have updateLayout() which will render the page and append to parentElement.
Sample code in update layout method:
var options = {} //Page options
if (!this._isLoaded) {
this._isLoaded = true;
WinJS.UI.Pages.render(this.uri, this._pageElement, options);
}
I found source of my problem. In page /pages/bookmarks/sectionPage.html I had <div> with an id meant for holding my ListVIew. And I was getting win control for listview using document.getElementById("listViewId").winControl. This is wrong, because then I had three divs with same id (each for every section), so getElementById was always returning same list (the one on the first section).
So I changed getting of the wincontrol to
var discussionList = document.querySelector("#" + contentHost + " .disucssionsListView").winControl;
where contentHost depends on data-win-options received from main page and everything works as expected.

Yii2 Abnormal behavior - update div via ajax call with a jui tab widget of a render ajax action

Good day folks,
I am having an issue with Yii2, dunno whats goin on after searching online haven't found an answer.
Updated Question with more details
Here is a summary I am trying to change div content of my view via an ajax call to a controller action – the controller action I am calling does nothing but renders another view file which contains a Jui Tab.
The problem is it loads the home page + my Content at a lower part not processed.
If I visit the URL of the action that the ajax request calls, it displays properly with no issues – When I try to append it to my div on another view, this problem occurs.
Here are screenshots of my view
Page Displaying correctly on visiting URL
https://www.dropbox.com/s/77ovpl6fnznjs1p/Page%20displaying%20correctly%20on%20visiting%20URL.png?dl=0
Updating div with the rendered view displays content in a wrong manner
https://www.dropbox.com/s/6nld4wk1p9pkhz9/Screenshot%20of%20the%20update%20view.png?dl=0
A- Initial View Code
Here is my first view code – Contains a div that you click to fireup the ajax call and another div called content which gets the response
brense.PHP
<?php
use yii\helpers\Html;
use yii\jui\Tabs;
?> <div style="background: blue; cursor: pointer; width:100px;" id="brense">Click ME</div><div id="content">Content</div>
B- Ajax (JS File) `$('#brense').click(function(){
alert('click Received');
$.ajax({
url:'index.php?r=assignments/get-me2',
Type:'GET',
success:function(data){
alert("bombo");
$('#content').append('<div>Appended Content</div>');
$('#content').html(data);
}
});
});
`
C- Controller Action – Called by Ajax
public function actionGetMe2(){
return $this->renderAjax('tab');
}
D- Tab’s View that should be loaded inside the div content
<?php
use yii\helpers\Html;
use yii\jui\Tabs;
?>
<div>
<?php echo Tabs::widget(
['items'=>[
['label'=>'One','content'=>'Content 1'],
['label'=>'Two ','content'=>'Content 2'],
],
]
);
?>
</div>
Ok, here is the problem. Yii and Yii2 have an automatic numbering of elements. It has elements that are called w0, w1, w2. In a normal page you have w0 1 time, Yii takes care of that. Because you bring in code with Ajax, the page is actually a new page, so it has it's own w0 element. if you take a look at the code that it has it calls
$('#w0').tabs();
Now that works fine when you look at the page alone, but it will not work ok at all on your page because after inserting the content on the page you have 2 w0 elements. It basically calls the tab on the first one of them (in my test it was the nav bar) and that messes it up. The solution is to give the tabs an id.
So your tab.php file should be:
<?php
use yii\helpers\Html;
use yii\jui\Tabs;
?>
<div>
<?php echo Tabs::widget(
[
'id' => 'tabs',
'items'=>[
['label'=>'One','content'=>'Content 1'],
['label'=>'Two ','content'=>'Content 2'],
],
]
);
?>
</div>
This should solve your problem, but you migth have other problems too. Like loading jquery and jquery ui 2 times, 1 with the main page the other with your ajax. Now STOP using renderAjax you should use renderPartial.
Your code should be: in the main view file:
<?php
use yii\jui\JuiAsset;
JuiAsset::register($this);
?>
<div style="background: blue; cursor: pointer; width:100px;" id="brense">Click ME</div><div id="content">Content</div>
<?php
$script = <<<EOD
$('#brense').click(function(){
alert('click Received');
$.ajax({
url:'index.php?r=site/get-me2',
Type:'GET',
dataType: 'html',
success:function(data){
$('#content').html(data);
$('#tabs').tabs();
}
});
});
EOD;
$this->registerJs($script);
I am registering jquerui ui asset at the top, if you already have it loaded it will not load it again. I have a function that brings over the ajax, and that function also calls $('#tabs').tabs(); to actually create the jquery ui tabs.
Your controller
public function actionGetMe2(){
return $this->renderPartial('tab');
}

Dynamically Injecting Pages with JQuery Mobile and Json

and thanks for looking at my question. I am new to HTML, JQuery, and JSon. I am trying to teach myself with some online tutorials and www.lynda.com training. I'm trying to make a glossary that dynamically displays a list of terms on page, and when clicked displays the term in the header and the definition below that. After searching and experimentation I've made progress, I've got my ul populating from the JSon object and linked to the display page. But I am at a loss as how to get the display page working. I thought the answer was in here: http://jquerymobile.com/demos/1.1.1/docs/pages/page-dynamic.html but I can't seem to pull it off, even in Dreamweaver.
Here is the JSFiddle: http://jsfiddle.net/LParker/PSntK/3/
HTML:
<!-- Glossary -->
<div data-role="page" id="glossary">
<div data-role="header">
<h3>
Glossary
</h3>
</div>
<ul data-role='listview' data-inset='true' id='resultsList'>
<!-- keep empty for dynamically added items -->
</ul>
</div>
<!-- display -->
<div data-role="page" id="display">
<div data-role="header">
<h3>
Name Goes Here
</h3>
</div>
<div data-role="content">
<div>Definition goes here</div>
</div>
JavaScript:
var jsonObject = {
"results": [{
"term": "Term One",
"definition": "This is the definition for Term Two",
},
{
"term": "Term Two",
"definition": "This is the definition of Term Two",
}, {
"term": "Term Three",
"definition": "This is the definition for Term Three",
}],
"ok": "true"
}
var resultLength = jsonObject.results.length;
var listItems = [];
for (var i = 0; i < resultLength; i++) {
var term = jsonObject.results[i].term;
//Add result to array
listItems.push("<li><a href='#display'>" + term + " </a></li>");
}
//Append array to list and refresh
$('#resultsList').append(listItems.join(' '));
$('#resultsList').listview('refresh');
Any help would be appreciated!
First of all lets get a few things out of the way:
Ditch extra commas after each definition member of your json object.
Put your #resultsList listview in a <div data-role="content"></div> container.
Provide the means to navigate from #display page back to #glossary page e.g. by adding a standard jQM back button <a data-role="button" data-rel="back" data-icon="back">Back</a> in the header of the #display page.
While working with jQM you need to use proper event handlers
For brevity I renamed your variable jsonObject to json.
You can populate the listview in a more succinct way:
$.each(json.results, function(i, term){
$('#resultsList').append('<li>' + term.term + '</li>')
});
$('#resultsList').listview('refresh');
Now in that particular case IMHO you don't need to inject pages (although it certainly possible) you can just change content in #display page on pagebeforeshow event.
For that to happen, since your json object globally available, you can just get an index of a clicked list item, pass it to your #display page, use it to access results array of your json object to extract and show term and it's definition.
The simplest way to pass an index is to use a global variable which you set in a click event handler.
var currentItem = 0;
...
$('#resultsList li').click(function(){
currentItem = $(this).index();
});
Now in pagebeforeshow event you do
$('#display').on('pagebeforeshow', function(){
$(this).find('[data-role=header] .ui-title').text(json.results[currentItem].term);
$('#definition').html(json.results[currentItem].definition);
});
Finally here is working jsFiddle for you.