Angular 2 Access Component Defined by Template - angularjs

I'm using Ionic as an example for this, but I figure it's a general Angular 2 question.
page1.ts
import {Page} from 'ionic-angular';
#Page({
templateUrl: 'build/pages/page1/page1.html'
})
export class Page1 {
constructor() {
}
}
page1.html
<ion-navbar *navbar>
<ion-title>Tab 1</ion-title>
</ion-navbar>
<ion-content padding class="page1">
<ion-slides pager>
<ion-slide>
<h3>Thank you for choosing the Awesome App!</h3>
<p>
The number one app for everything awesome.
</p>
</ion-slide>
<ion-slide>
<h3>Using Awesome</h3>
<div id="list">
<h5>Just three steps:</h5>
<ol>
<li>Be awesome</li>
<li>Stay awesome</li>
<li>There is no step 3</li>
</ol>
</div>
</ion-slide>
<ion-slide>
<h3>Any questions?</h3>
</ion-slide>
</ion-slides>
</ion-content>
How do I programatically reference the ion-slides object from the constructor of the Page1 class?
I had assumed via some sort of #reference but I'm not sure of the syntax

If ion-slides is a component or a directive, and there is only one instance in the template, use #ViewChild:
#ViewChild(IonSlides) ionSlides:IonSlides;
This assumes the component class name is IonSlides.
this.ionSlides will not be available in the constructor. It will be available in lifecycle hook ngAfterViewInit(), as documented in the ViewChild API page:
ngAfterViewInit() {
console.log(this.ionSlides);
}

Yes, it's an angular question.You can use #ViewChild decorator to access child component. like:
#ViewChild(CountdownTimerComponent)
private _timerComponent:CountdownTimerComponent;
See the angular2 doc for the detail, not to hard.
https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-view-child
PS. if you have more than on components in same type like Button, use
#ViewChildren(Button) buttons: QueryList<Button>;

Related

components load before call angularjs

I am working on angular js components there are two components that will called when their respective button is clicked
Issue: when the page loads both components are initialized , but in real they should be initialized when I click on the respective component
example:
index.html
<div class='breadcrumbs'>
<div class='inner'>
<ul class='cf' style=" margin-top: 0px;">
<li ng-click="WizardsViewerCtrl.createFirst()">
</li>
<li ng-click="WizardsViewerCtrl.createSecond()">
<span>Arrange Questions</span> </a>
</li>
</ul>
</div>
</div>
<div ng-show="viewFirstRoute">
<first-component></first-component>
</div>
<div ng-show="viewSecondRoute">
<second-component></second-component>
</div>
index.js
$scope.viewFirstRoute=false;
$scope.viewSecondRoute=false;
function createFirst() {
$scope.viewFirstRoute=true;
$scope.viewSecondRoute=false;
}
function createSecond() {
$scope.viewFirstRoute=false;
$scope.viewSecondRoute=true;
}
problem is when this page index.html is loaded ,both components are initialized
first.component.js
angular
.module('AOTC')
.component('firstComponent', {
templateUrl: 'first.html',
controllerAs: 'firstCtrl',
controller:(function ($scope) {
console.log("first component loaded");//it prints while index.html is loaded even i didn't clicked on this component
})});
second.component.js
angular
.module('AOTC')
.component('secondComponent', {
templateUrl: 'second.html',
controllerAs: 'secondCtrl',
controller:(function ($scope) {
console.log("second component loaded");//it prints while index.html is loaded even i didn't clicked on second component
})});
summarizing: two components on same route must be initialized when I click on the respective component , but behavior noticed components are loaded as soon as route is loaded it doesn't care about the click, see comments in the JS file
Use ng-if instead of ng-show. it should fix the issue.
<div ng-if="viewFirstRoute">
<first-component></first-component>
</div>
<div ng-if="viewSecondRoute">
<second-component></second-component>
</div>
ng-show: it will add component to DOM but set its display property to none.
ng-if: Will add or remove component from DOM conditionally.

Can a CSS class selector be applied to a component?

I have the following Plunker that uses ui-router and Angular's 1.6x new component feature.
The state 'userRegister' becomes active then initialises the 'userRegister' component. This component injects a new <user-register/> into the <ui-view> then injects the HTML contents of the ng-template script block, which is all working fine.
The final DOM ends up being:
<ui-view class="ng-scope">
<user-register class="ng-scope ng-isolate-scope">
<h1 class="header">Create account</h1>
</user-register>
</ui-view>
However, I cannot find a way to add a CSS class selector to the <user-register/> tag.
e.g. using a class selector called .example I'd like to achieve the following:
<user-register class="example ng-scope ng-isolate-scope">...<user-register/>
Any ideas please?
Sure you could always wrap the template on a div and put the class there.
If don't want to do it, you can inject the $element and use the $postLink function to add the class you need:
.component('userRegister', {
templateUrl: '/views/user-register',
controller: function($element) {
this.$postLink = function() {
$element.addClass('example');
}
}
})
Here is the working plunker:
https://plnkr.co/edit/VuWu8L9VqrgJRGnxItY2?p=preview
Final DOM:
<user-register class="ng-scope ng-isolate-scope example">
<h1 class="header">Create account</h1>
</user-register>

Cannot get slidesCount from $ionicSlideBoxDelegate

I am creating a mobile app with Ionic framework. I am using ion-slide-box
<ion-slide-box class="slidebox" on-slide-changed="change(index)">
<ion-slide>
<img src="img/johnson.jpg" id="album">
</ion-slide>
<ion-slide>
<img src="img/eiston.jpg" id="album">
</ion-slide>
<ion-slide>
<img src="img/vera.jpg" id="album">
</ion-slide>
<ion-slide>
<img src="img/max.jpg" id="album">
</ion-slide>
</ion-slide-box>
I want to know the total slide number
$scope.change= function(index){
console.log('currentindex '+index); //i get the correct current index
console.log($ionicSlideBoxDelegate.currentIndex()); //I get undefined
alert($ionicSlideBoxDelegate.slidesCount()); //I get undefined
}
I tried a lot of things, nothing seems to be working with $ionicSlideBoxDelegate? Is it deprecated?
You should use <ion-slides> instead of <ion-slide-box>, then try to add a modal to slider param i.e:
<ion-slides options="options" slider="data.slider">
<ion-slide-page>
<div><h1>some Text</h1></div>
</ion-slide-page>
</ion-slides>
then in your controller you will use 'data.activeIndex' to get the current index using a handler as:
$scope.$on("$ionicSlides.slideChangeEnd", function(event, data){
alert( data.activeIndex );
});
you can consult the doc:
http://ionicframework.com/docs/api/directive/ionSlides/
Ionic's new slide is derived from swiper.
According to ionic's documentation it is deprecated in favour of the newer component.
You will have to do a bit of research into how to use the newer component as it is not documented very well.

Ionic collection-repeat affecting active classes

I have ng-class inside of my ion-list if the user clicks an item it adds the class selected. The problem when using collection-repeat is its managing the DOM and changing the selected class as I scroll.
<ion-list>
<ion-item collection-repeat="contact in contacts | filter:filters" class="contact" ng-click="pickContact($index, $element, this.contact)" ng-model="contactModel" ng-class="{'selected': contact.selectedContact}" toggle-contacts="selected" collection-item-height="150" collection-item-width="'33.3%'">
<div ng-if="contact.photo.type == 'img'" class="contact-img">
<img ng-src="{{contact.photo.value}}.png" alt="">
</div>
<div ng-if="contact.photo.type == 'text'" class="contact-text-placeholder">
{{contact.photo.value}}
</div>
<div class="contact-name">
{{contact.name}}
</div>
</ion-item>
</ion-list>
How can I avoid this from happening? I want the class to stick.
The solution was to add the class into the data itself.

AngularJS UI Bootstrap Tabs that support routing

I would like to use AngularJS UI Bootstrap Tabs in my project, but I need it to support routing.
For example:
Tab URL
--------------------
Jobs /jobs
Invoices /invoices
Payments /payments
As far as I can tell from the source code, the current tabs and pane directives doesn't support routing.
What would be the best way to add routing?
To add routing you typically use an ng-view directive. I'm not sure it's easy enough to modify angular UI to support what you're looking for, but here's a plunker showing roughly what i think you're looking for (it's not necessarily the best way of doing it - hopefully someone can give you a better solution or improve on this)
Use data-target="#tab1". Worked for me
This answer really helped me http://odetocode.com/blogs/scott/archive/2014/04/14/deep-linking-a-tabbed-ui-with-angularjs.aspx (very simple but powerful solution)
I also have this requirement and I'm doing something similar to the answer provided by Chris, but I'm also using AngularUI router, because ngRouter does not support nested views and it is possible you'll have the tabs content view inside another view (I did) and that won't work with ng-view.
you could pass your own custom key value pairs in the route definition and achieve this.
here's a good example:
http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm
Agree with the use of UI-Router which tracks states and works great with nested views. Speaking particularly of your Bootstrap tabs issue there is a great implementation that leverages UI Router: UI-Router Tabs
If you have a route called settings and you want to have tabs in that settings page something like this works.
<div class="right-side" align="center">
<div class="settings-body">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#!/settings#private_email">Private email</a></li>
<li><a data-toggle="tab" href="#!/settings#signature">Signature</a></li>
<li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
</ul>
<div class="tab-content">
<div id="private_email" class="tab-pane fade in active">
<div class="row" ng-controller="SettingsController">
<div>
<button class="btn btn-primary" ng-click="activatePrivateEmail()">Activate email</button>
<button class="btn btn-danger">Deactivate email</button>
</div>
</div>
</div>
<div id="signature" class="tab-pane fade">
<textarea ui-tinymce="tinymceOptions" ng-model="signature"></textarea>
<div class="send-btn">
<button name="send" ng-click="" class="btn btn-primary">Save signature</button>
</div>
</div>
<div id="menu2" class="tab-pane fade">
<h3>Menu 2</h3>
<p>Some content in menu 2.</p>
</div>
</div>
</div>
</div>
I got tabs with routing working the following way.
It's able to do everything you want from dynamic tabs, and it's actually very simple.
Tabs with a ui-view, so it can dynamically load templates,
Update routing in URL
Set history state
When directly navigating to a route with a tabbed view, the correct tab is marked as active.
Define the tabs with a parameter in your router
.state('app.tabs', {
url : '/tabs',
template : template/tabs.html,
})
.state('app.tabs.tab1', {
url : '/tab1',
templateUrl : 'template/tab1.html',
params : {
tab : 'tab1'
}
})
.state('app.visitors.browser.analytics', {
url : '/tab1',
templateUrl : 'template/tab2.html',
params : {
tab : 'tab2'
}
})
The tabs template (tabs.html) is
<div ng-controller="TabCtrl as $tabs">
<uib-tabset active="$tabs.activeTab">
<uib-tab heading="This is tab 1" index="'tab1'" ui-sref="app.tabs.tab1"></uib-tab>
<uib-tab heading="This is tab 2" index="'tab2'" ui-sref="app.tabs.tab2"></uib-tab>
</uib-tabset>
<div ui-view></div>
</div>
Which is paired with a very simple controller for getting the current active tab:
app.controller('TabCtrl', function($stateParams) {
this.activeTab = $stateParams.tab;
})
just a small add to accepted answer:
i needed to keep the current tab at page refresh so i used a switch like this:
$scope.tabs = [
{ link : '#/furnizori', label : 'Furnizori' },
{ link : '#/total', label : 'Total' },
{ link : '#/clienti', label : 'Clienti' },
{ link : '#/centralizator', label : 'Centralizator' },
{ link : '#/optiuni', label : 'Optiuni' }
];
switch ($location.path()) {
case '/furnizori':
$scope.selectedTab = $scope.tabs[0];
break;
case '/total':
$scope.selectedTab = $scope.tabs[1];
break;
case '/clienti':
$scope.selectedTab = $scope.tabs[2];
break;
case '/centralizator':
$scope.selectedTab = $scope.tabs[3];
break;
case '/optiuni':
$scope.selectedTab = $scope.tabs[4];
break;
default:
$scope.selectedTab = $scope.tabs[0];
break;
}
This aught to be able to do what you want:
https://github.com/angular-ui/ui-router

Resources