Is it possible to use angular aria for aria-expanded? - angularjs

I searched on the Internet and the Angular Aria documentation - it didn't mention about aria-expanded or aria-selected?
Is there a way of implementing this?
<a href ng-aria={'expanded': selected} & ng-aria={'selected': selected}></a>
which will make:
<a href aria-expanded="true" aria-selected="true"></a>
Thanks.

I used ng-bootstrap to do it. For example:
HTML
<p>
<button type="button" class="btn btn-outline-primary" (click)="isCollapsed = !isCollapsed"
[attr.aria-expanded]="!isCollapsed" aria-controls="collapseExample">
Toggle
</button>
</p>
<div id="collapseExample" [ngbCollapse]="isCollapsed">
<div class="card">
<div class="card-body">
You can collapse this card by clicking Toggle
</div>
</div>
</div>
TYPESCRIPT
import { Component } from '#angular/core';
#Component({
selector: 'ngbd-collapse-basic',
templateUrl: './collapse-basic.html'
})
export class NgbdCollapseBasic {
public isCollapsed = false;
}
Source: https://ng-bootstrap.github.io/#/components/collapse/examples

No need for a directive to set aria-expanded. Just use an expression:
link
<p ng-show="selected">content<p>

Related

angularjs ng-model not binding after state change

There are three states defined in my project called "/projects","/pages" and "/settings". The function given below works without any problem in case not state changing (I also tried with ngRoute but the result was same). But when I started to change states and then get back to the same page this function not binding data to the modal box. [There is no error occurred in this situation!] (when I'm refreshing page it turns back to normal).
My app.js file
// Dependencies wired beforehand.
/** #var {Object} projects Page management page state */
var projects = {
name: 'projects',
url: '/projects',
templateUrl: TEMPLATES_DIR + 'projects.html',
controller: 'projects'
};
/** #var {Object} pages Page management page state */
var pages = {
name: 'pages',
url: '/pages',
templateUrl: TEMPLATES_DIR + 'pages.html',
controller: 'pages'
};
/** #var {Object} settings Settings page state */
var settings = {
name: 'settings',
url: '/settings',
templateUrl: TEMPLATES_DIR + 'settings.html',
controller: 'settings'
};
$stateProvider.state(projects);
$stateProvider.state(pages);
$stateProvider.state(settings);
Function from projects controller: (This function binds data to modal box)
$scope.getProjectImages = function(id) {
$scope.projectId = id;
projectsFactory.getImages(id).then(function(response) {
$scope.images = response.data;
//I can see that it's holding array but it's not binding data to modal box anymore when the state changed
alert($scope.images);
});
};
template file (UPDATED):
<div id="project-image-manager" class="uk-modal-container uk-position-z-index" uk-modal="stack: true; bg-close: false; container: false">
<div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" ng-click="resetProjectImagesModal()" uk-close></button>
<div class="uk-grid-divider" uk-grid>
<div class="uk-animation-slide-bottom-medium uk-width-1-3#m uk-margin-medium-top">
<h3>Image Attachment<span class="uk-display-block uk-text-small">File Management</span></h3>
<form method="post" enctype="multipart/form-data">
<button ngf-select="uploadImage($files)" class="uk-button uk-margin-bottom uk-button-default uk-text-capitalize uk-text-left" accept="image/*" multiple>Upload Images<span class="uk-icon uk-margin-small-left" uk-icon="icon: image"></span></button>
</form>
<p>{{ errorMsg }}</p>
<progress class="uk-progress" value="{{ progress }}" max="100"></progress>
<ul class="uk-list uk-text-small uk-margin-large-top uk-list-divider">
<li ng-repeat="file in files">{{ file.name }}</li>
</ul>
</div>
<div class="uk-width-expand#m">
<div class="uk-background-default uk-padding-bottom uk-width-expand uk-text-center" ng-if="images.length">
<p class="uk-animation-slide-left-small" ng-if="sortableImages.disabled">
<span class="uk-icon uk-margin-small-right" uk-icon="icon: lock"></span><a class="uk-text-muted uk-link-reset" ng-click="sortableImages.disabled = false">Unlock to sort images</a>
</p>
<p class="uk-animation-slide-left-small" ng-if="!sortableImages.disabled">
<span class="uk-icon uk-margin-small-right" uk-icon="icon: unlock"></span><a class="uk-text-muted uk-link-reset" ng-click="sortableImages.disabled = true">Lock sorting</a>
</p>
</div>
<h3 class="uk-animation-fade uk-text-center uk-text-muted uk-margin-large-top uk-align-center" ng-show="!images.length">
<span class="uk-icon uk-display-block" uk-icon="icon: image; ratio: 4"></span>This project has no images.
</h3>
<div ng-if="images.length">
<ul class="uk-animation-fade uk-list uk-margin-medium-top" ng-model="images" ui-sortable="sortableImages">
<li class="uk-margin-medium-bottom" ng-model="images" ng-repeat="image in images">
<div uk-grid>
<div class="uk-width-1-2#m uk-width-1-3#s mobile-width-image sortable-image-item">
<div class="uk-background-cover uk-width-1-4#xs uk-panel uk-flex uk-flex-center uk-flex-middle image-thumbnail-height" style="background-image: url({{ uploadPath }}{{ image.url }});">
</div>
</div>
<div class="uk-width-1-2#m uk-width-2-3#s mobile-width-text">
<p class="uk-text-muted" ng-if="!image.description.length">No description given.</p>
<p>{{ image.description }}</p>
<hr class="uk-divider-small uk-margin-top uk-margin-bottom">
<ul class="uk-iconnav uk-padding-remove-left">
<li>
<a ng-click="getImageDescription(image.id)" uk-icon="icon: file-edit" uk-toggle="target: #add-description"></a>
</li>
<li>
<a ng-click="removeImage(image)" uk-icon="icon: trash"></a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
What's wrong with that code? My last plan giving up doing in SPA and go with traditional routing. :D Thanks for your help.
I solved out. DOM appended container option for modal box prevents data binding. It's UIkit CSS Framework related problem.
Solution: Set container option to false.
Here is the solution:
uk-modal="...other options.. container: false">
UIkit js reference:
container String true Define a target container via a selector to specify where the modal should be appended in the DOM. Setting it to false will prevent this behavior.

Separation components and codereview in AngularJS

I started read about modules, components, directives. I would like to ask you to check the code and say how I could improve it. The main thing for me is to figure out how I can improve the transparency of this code. I would also like to learn how to split this code into files, and how it should look like the file structure in this case. I heard that I should make one file for components, But how should it look in the inside?
I would really be grateful for help.
because the most important in the life of the programmer is the code review! :)
(function () {
angular.module('app.navbar', [])
.component('navbar', {
bindings: {
user: '<'
},
controller: function ($scope) {
var navbar = this;
this.$onInit = function () {
navbar.toggle = false;
};
this.activeMenu = function (name, $event) {
this.blockClosingList($event);
if (navbar.toggle === true && $scope.name == name) {
navbar.toggle = !navbar.toggle;
}
else if (navbar.toggle === false) {
navbar.toggle = !navbar.toggle;
}
$scope.name = name;
}
this.blockClosingList = function ($event) {
$event.stopPropagation();
}
},
controllerAs: 'navbar',
template: `
/////// MENU LEFT SIDE ///////
<div class="main-navbar">
<div class="menu-left">
<div class="btns">
<span class="glyphicon glyphicon-align-left btn__glyph"></span>
<span class="btn--name">Tablice</span>
</div>
<div class="btns navbar__search">
<span class="glyphicon glyphicon-search"></span>
</div>
</div>
<div class="navbar__logo">
<span class="navbar--logo">Tasker</span>
</div>
/////// MENU RIGHT SIDE ///////
<div class="menu-right">
<a href="#" ng-click="navbar.activeMenu('Create', $event);">
<div class="btns">
<span class="glyphicon glyphicon-plus"></span>
</div>
</a>
<!-- MENU CREATE -->
<div class="menu menu--create" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Create' && navbar.toggle === true}">
<!--close-->
<menu-create></menu-create>
</div>
<!---->
<!--MENU CREATE BOARD-->
<div class="menu cb__menu-coordinate menu--create-board" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'menuCreateBoard' && navbar.toggle === true}">
<span class="settings-menu__header-title">Utwórz Tablicę</span>
<div class="menu__wrapper--create-board center-block">
<menu-create-board></menu-create-board>
</div>
</div>
<!---->
<a href="#" ng-click="navbar.activeMenu('Notice', $event);">
<div class="btns">
<span class="glyphicon glyphicon-bell"></span>
</div>
</a>
<!--NOTIFICATIONS-->
<div class="menu menu--notice" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Notice' && navbar.toggle === true}">
<notifications></notifications>
</div>
<!---->
<a href="#" ng-click="navbar.activeMenu('Profile', $event);">
<div class="btn__circle">
<span class="btn--circle">B</span>
</div>
</a>
<!--MENU PROFILE -->
<div class="menu menu--avatar" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Profile' && navbar.toggle === true}">
<profile-menu></profile-menu>
</div>
</div>
</div>
<!---->
`
})
.component('profileMenu', {
require: {
parent: '^navbar'
},
template: `
<!--close-->
<span class="settings-menu__header-title">
{{$ctrl.parent.user.username}} {{$ctrl.parent.user.role}}
</span>
<ul class="menu__avatar--list">
<li>
Profil
</li>
<li>
<a href="/{{$ctrl.parent.user.username}}">
Karty</a>
</li>
<li>
<a href="/{{$ctrl.parent.user.username}}">
Ustawienia</a>
</li>
<li>
<a href="/logout">
Wyloguj</a>
</li>
</ul>
`
})
.component('notifications', {
require: {
parent: '^navbar'
},
template: `
<!--close-->
<span class="settings-menu__header-title">Powiadomienia</span>
<div class="menu__field--placeholder">
<span>Brak powiadomień</span>
</div>
`
})
.component('menuCreateBoard', {
require: {
parent: '^navbar'
},
template: `
<form>
<div class="form-group">
<label for="">Tytuł</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label for="">Zespół</label>
<input type="text" class="form-control">
</div>
<span class="bottom--create-board">Ta tablica będzie Prywatna. Zmień</span>
<button class="btn btn-success">Utwórz</button>
</form>
`
})
.component('menuCreate', {
require: {
parent: '^navbar'
},
template: `
<span class="settings-menu__header-title">Utwórz</span>
<ul class="menu__create--list">
<li>
<a href="#" ng-click="$ctrl.parent.activeMenu('menuCreateBoard', $event);">
<div class="menu__wrapper-create">
<span class="menu-create__heading">Utwórz tablicę</span>
<span class="menu-create__desc">Tablica składa się z kart uporządkowanych w listach. Użyj jej do zarządzania projektami, śledzenia informacji i organizowania wszystkiego.</span>
</div>
</a>
</li>
<li>
<a href="#">
<div class="menu__wrapper-create">
<span class="menu-create__heading">Utwórz zespół</span>
<span class="menu-create__desc">Zespół składa się z ludzi i tablic. Organizuj z jego pomocą firmę, swoją drugą pracę, plany dla rodziny i spotkania z przyjaciółmi.</span>
</div>
</a>
</li>
</ul>
`
})
})();
https://gist.github.com/Turqus/2a791c6b86adfc8b6732711eaec2e23d
in main app:
var App = angular.module('TodoListApp', ['dndLists', 'app.navbar']);
First I would advise you to go here and learn how to use webpack:
https://webpack.github.io/
After you learn how to bundle your files, you should separate templates out of your js files and use templateUrl to load template - you can webpack template loader - works very good.
Then to improve it even further you can learn to use javascript export (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) functionality and separate your code in files.
I like the following directory structure (for example you could use navbar instead of my-component-name):
/my-component-name - directory
my-component-name.component.js - contains my component bindings and templateUrls, also here we import controller for that particular component.
my-component-name.controller.js - sets up controller for component
my-component-name.html - template
my-component-name.scss/less - less/sass file containing isolated styles for that particular component - wrapped in my-component-name {...}
index.js - contains all code put together declaration of angular module, all imports (component,services, directives) and dependencies.
index.js example (you can name it navbar-module.js):
import NavbarComponent from './navbar.component'; // <- here you import component
const NavbarModule = angular
.module('navbar', [])
.component('navbar', NavbarComponent) // <- here you define your component
.name;
export default NavbarModule;
navbar.component.js example:
import templateUrl from './navbar.html';
import controller from './navbar.controller.js'
const NavbarComponent = {
bindings: {
user: '<'
},
templateUrl, // just a shorthand for writing templateUrl: templateUrl
controller, // same as above
}
export default NavbarComponent;
and finally navbar.controller.js:
class NavbarController {
constructor($scope, $timeout) {
this.$scope = $scope;
this.$timeout = $timeout;
}
$onInit() {
// set up your on init code here
this.toggle = true;
}
// set up your functions on controller - they will behave same and you will be able to access them via $ctrl.activeMenu() or $ctrl.blockClosingList() in your templates
activeMenu (name, $event) {
this.blockClosingList($event);
if (this.toggle === true && this.$scope.name == name) {
this.toggle = !this.toggle;
}
else if (this.toggle === false) {
this.toggle = !this.toggle;
}
this.$scope.name = name;
}
blockClosingList($event) {
$event.stopPropagation();
}
}
NavbarController.$inject = ['$scope', '$timeout']; // inject here and put $scope parameter in your constructor
export default NavbarController;
navbar.html - just use your html code it should work fine.
If you need to create some inner functions and keep access to this (controller) you can use arrow functions instead of function (param) {...} just use (param)=>{...} and inside brackets you will have scope of your controller.
One more thing - isolate your components as much as you can and try to communicate to parent components via $emit/$broadcasts instead of requiring parent component like in your example.
Keep in mind what I wrote above is in no way tested and most likely has bugs.
De facto best read about component based architecture in AngularJS can be found here, Todd Motto's styleguide:
https://github.com/toddmotto/angularjs-styleguide

How to dynamically creating components With Angular 1.5 using a Generic Component?

I need to create a component +/- that contains an "Add button" to allow duplicates of a given component (with its HTML template and logic) and every component has a "Delete button", for that I want to create a generic component which I can pass to it whatever component I want, look at image below
I used transclude, but still not convinced with that, as it's impossible to access the data of every child. This is my code, there is any other way to achieve that?
JS component
class AddRemoveComponent {
/**
* Inject all the required services.
*
*/
constructor() {
'ngInject'
}
$onInit() {
this.items = []
}
/**
*
* On add component click.
*/
addComponent() {
// TODO
debugger
this.items.push({})
}
/**
*
* On remove component click.
*/
removeComponent(index) {
// TODO
this.items.splice(index, 1)
}
}
export const addRemoveComponent = {
template: require('./myiad-add-remove.html'),
controller: AddRemoveComponent,
transclude: {
body: 'iadComponentBody'
},
bindings: {
title: '#',
items: '='
}
}
HTML component
<div class="row">
<div class="text-center">
<button class="btn btn-primary"
ng-click="$ctrl.addComponent()">
<span class="fa fa-plus"></span>
</button>
<span class="numeric-stepper">{{ $ctrl.items.length }}</span>
</div>
</div>
<div class="row margin-top-20" ng-repeat="item in $ctrl.items">
<div ng-transclude="body"></div>
<div class="form-group">
<div class="myiad-remove-bloc col-xs-12 text-center" ng-click="$ctrl.removeComponent($index)">
<span translate>iadMyIadAddRemove.delete</span> {{ $ctrl.title }}<span class="fa fa-times"></span>
</div>
</div>
</div>
How to use it :
<iad-my-iad-add-remove title="TODOLABEL" items="$ctrl.project.realEstateProjectMotivation.realEstateProjectOnSales">
<iad-component-body>
<iad-agent-my-iad-project-motivations-how-sale-current-capital-item
project-references="$ctrl.projectReferences">
</iad-agent-my-iad-project-motivations-how-sale-current-capital-item>
</iad-component-body>
</iad-my-iad-add-remove>
Thanks :)

Unable to change ng-href onClick event

I have a footer with a button in my angular app. The button has an ng-href attribute which should change during the ng-click event to affect the routing mechanism. For some reason I cant make this work. The ultimate goal is to append numbers, 1 to five each button click.
The footer is a component:
app.component('footerx', {
bindings: {
},
templateUrl: 'views/footer.html',
controller: function () {
this.buttonText = "Next";
var self = this;
var i = 1;
this.changeHref= function () {
self.questionIndex=i;
i++;
}
}
});
Footer HTML:
<footer class="footer">
<div class="container">
<a class="btn btn-primary" ng-click="$ctrl.changeHref()" ng-href="#/quiz/{{questionIndex}}" id="btn">{{$ctrl.buttonText}}</a>
</div>
</footer>
Routing JS part:
...
.when("/quiz/:index", {
templateUrl: "views/questionPage.html",
controller: "questionController"
})
...
EDIT:
Right now the url does not fully change. This means it does not have the questionIndex. It looks like this:
http://localhost/myApp/#/quiz/
Use "#/quiz/{{$ctrl.questionIndex}}
<footer class="footer">
<div class="container">
<!-- REMOVE
<a class="btn btn-primary" ng-click="$ctrl.changeHref()"
ng-href="#/quiz/{{questionIndex}}" id="btn">
{{$ctrl.buttonText}}
</a>
-->
<!--ADD -->
<a class="btn btn-primary" ng-click="$ctrl.changeHref()"
ng-href="#/quiz/{{$ctrl.questionIndex}}" id="btn">
{{$ctrl.buttonText}}
</a>
</div>
</footer>

Directive not loading inside ng-repeat with ng-if

I'm creating a Masonry layout populated with images and videos and since the images-loaded directive doesn't work I'm trying to come up with a quick work around. (https://github.com/passy/angular-masonry/issues/116)
The problem I have is the link function is never fires. I'm wondering if it has something to do with ng-if's being encapsulated by an ng-repeat because according to this plunkr (http://jsfiddle.net/q05gret0/) the link function should run whenever ng-if evaluates to true
<div style="margin:auto;" images-loaded="false"
masonry="{isFitWidth: true}">
<div class="masonry-brick media-block"
ng-repeat="mediaItem in media">
<div ng-if="mediaItem.type === 'image/jpeg' || mediaItem.type === 'image/png'">
<img alt="image" class="fill-width" ng-src="{{MEDIA_URL + mediaItem.urlThumbnail}}" data-loaded>
</div>
<div ng-if="mediaItem.type === 'video/mp4'">
<video autoplay="true" loop="loop" muted="muted" data-loaded>
<div trust-url url="mediaItem.url"></div>
</video>
</div>
<div class="media-info container-fluid">
<div class="col-xs-9 no-padding">
<h5 class="media-title">{{mediaItem.name}}</h5>
</div>
<div class="col-xs-3 no-padding">
<button class="btn btn-sm btn-danger" ng-click="deleteMedia(mediaItem)"><i
class="fa fa-trash-o"></i></button>
</div>
</div>
</div>
</div>
And the directive in question:
.directive('dataLoaded', function dataLoaded() {
return {
restrict: 'A',
link: function (scope, iElement) {
console.log("linked!");
iElement.bind('load', function() {
scope.$broadcast("masonry.reload");
});
},
};
})
You are using the wrong directive name
<video autoplay="true" loop="loop" muted="muted" data-loaded>
"data-loaded" looks for a directive with a name "loaded". So you need rename directive to "loaded" or to change the attribute to "data-data-loaded". I'd prefer to rename the directive
Please replace this line:
.directive('dataLoaded', function dataLoaded() {
with that line:
.directive('loaded', function dataLoaded() {

Resources