I have CarsComponent that I multi time use ChartComponent in it's template as I mentioned in code snippet:
cars.component.html:
<div class="row" *ngIf="selectedItemId">
<div class="col-12 mb-2">
<report-chart [LegendData]="xAxisData1"
[SeriesData]="yAxisData1"
title="میزان خروج وسیله ی نقلیه از مراکز تولید"
barChartColor="#ad106c"
(onReportClick)="getProductReport()">
</report-chart>
</div>
<div class="col-12">
<report-chart [LegendData]="xAxisData2"
[SeriesData]="yAxisData2"
barChartColor="#3398DB"
title="میزان ورود وسیله نقلیه به مراکز فروش"
(onReportClick)="getSaleReport()">
</report-chart>
</div>
</div>
and and in my ChartComponent I use radio-button-group like this:
chart.component.html:
<nb-radio-group [(ngModel)]="selectedChart" class="d-flex justify-content-center">
<nb-radio class="d-flex justify-content-center"
*ngFor="let option of radioButtonsOptions"
[value]="option.value">
{{ option.label }}
</nb-radio>
</nb-radio-group>
my problem is when report-chart load in cars-component selected radio button only show in one instance and I want to prevent affection of two instance to each other
If I understand correctly you want to enable the ratio buttons only in the second child component and not the first.
The solution would be to pass a boolean input in the child component to show or not the ratio button.
Related
I am trying to access a Bootstrap card element so that I can hide its display when I use a search function. Currently I access the element inside the card in my to hide that when I collapse the cards when I do my filter search.
The problem with that is that there is a lot of white space that gets gets created from the Bootstrap element which increases as you select the cards closer to the bottom. The pictures below depict the problem. I will show you my unsuccessful solutions below too.
Here is what the page looks like uncollapsed:
Here is what the page looks like collapsed:
This is my HTML code for the section:
<div class="container pt-3 pb-3">
<div class="form-outline" id="customer-search-bar">
<input type="search" id="filter" class="form-control" placeholder="Search" aria-label="Search" >
</div>
<div class="card-lists">
<div class="row">
{% for data in raw.CustomerDataEntries %}
<div class="card col-sm-12 mb-3" id="card-perim">
<div class="card-body">
<h5 class="card-title">Customer ID: {{ data.ExternalId }}</h5>
<h5 class="card-title">Forename: {{ data.Fields.forename }}</h5>
<h5 class="card-title">Surname: {{ data.Fields.surname }}</h5>
<h5 class="card-title">Postcode: {{ data.Fields.post_code }}</h5>
<h5 class="card-title">Matches: {{ data.Matches }}</h5>
Details
Edit
</div>
</div>
{% endfor %}
</div>
</div>
</div>
This is my JavaScript code for the section:
let filter = document.querySelector('#filter');
filter.addEventListener('keyup', () => {
searchID();
});
function searchID() {
const input = filter.value.toUpperCase();
const cardContainer = document.querySelector('.card-lists');
const cardPerim = cardContainer.querySelectorAll('.card col-sm-12 mb-13');
// const cardPerim = cardContainer.querySelectorAll('#card-perim');
const cards = cardContainer.querySelectorAll('.card-body');
cards.forEach(card => {
//this option works, but does not target bootstrap container
card.style.display = 'none';
//here I am trying to change the css property, this does not work
// cardPerim.style.display = 'none';
//here I am trying to change the display property through bootstrap class attributes, this does not work
// cardPerim.className = "d-none card col-sm-12 mb-3";
card.querySelectorAll(".card-body h5.card-title").forEach(title => {
if (title.innerText.toUpperCase().indexOf(input) > -1) {
//this option works, but does not target bootstrap container
card.style.display = "block";
//here I am trying to change the css property, this does not work
// cardPerim.style.display = "block";
//here I am trying to change the display property through bootstrap class attributes, this does not work
// cardPerim.className = "card col-sm-12 mb-3 ";
}
});
});
}
Note that I try to unsuccessfully access the Bootstrap "card col-sm-12 mb-13" through its class name and id "card-perim". I also change its display property through changing the CSS style and through changing its Bootstrap class attributes, both unsuccessful.
How can I do it?
For cardContainer.querySelectorAll('.card col-sm-12 mb-13'), please change to cardContainer.querySelectorAll('.card .col-sm-12 .mb-13') for the class ref.
After the change, it should work.
I have this html template file, range-details-dialog.tpl.html
<div class="modal-header clearfix text-left">
<h5>Update Range</h5>
</div>
<div class="modal-body">
<form name="form" role="form" class="ng-pristine ng-valid" novalidate ng-submit="updateRange()">
<div class="form-group-attached">
<div class="row">
<div class="col-sm-12">
<div class="form-group form-group-default input-group p-l-10 p-r-10" ng-class="{ 'has-error' : form.$invalid }">
<p ng-show="form.rangeDaily.$error.min" class="help-block">Daily range more than £5</p>
</div>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-sm-8"></div>
<div class="col-sm-4 m-t-10 sm-m-t-10">
<button type="button" class="btn btn-primary btn-block m-t-5"
ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateRange()">Update</button>
</div>
</div>
</div>
Then I want to have another file forced-range-details-dialog.tpl.html
These two files could be one file instead with dynamically populated placeholders.
These are the places were substitution would be needed:
<h5>Update Range</h5> would become <h5>Update Forced Range</h5>
<p ng-show="form.rangeDaily.$error.min" class="help-block">Daily range more than £5</p>
would become:
<p ng-show="form.forcedRangeDaily.$error.min" class="help-block">Forced Daily range more than £5</p>
ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateRange()">Update</button>
, ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateForcedRange()">Update</button>
Is there a way to avoid having two separate template files for the above? Could you please provide some examples, links, or pointers as to how that can be achieved?
Also, I see in the answers that a solution would be to add a boolean parameter inside the component and then call it twice. I am not sure how to call the component though. I have pasted my component below:
angular.module('app.investment.rangeDetails')
.component('pxForcedLimitAmount', {
templateUrl: '/assets/js/apps/range/range-details-dialog.tpl.html',
bindings: {
amount: '<',
isRequest: '<?',
requestedAt: '<?',
#Input() isForced: boolean //<<----I added this based on answers below
},
controller: [function () {
var ctrl = this;
ctrl.$onInit = function () {
ctrl.isRequest = ctrl.isRequest === true || false;
};
}],
});
Seems like only the placeholders need to change, so you can use a variable to decide what placeholder to display on the template. For example:
isForced: boolean;
ngOnInit() {
this.isForced = true; // decide how you want to toggle this
}
on the template:
<h5 *ngIf="!isForced">Update Range</h5>
<h5 *ngIf="isForced">Update Forced Range</h5>
and
<p *ngIf="!isForced" ng-show="form.rangeDaily.$error.min" class="help-block">
Daily range more than £5</p>
<p *ngIf="isForced" ng-show="form.forcedRangeDaily.$error.min" class="help-block">
Forced Daily range more than £5</p>
you can do the same for other tags as well.
From the comments, one way to "determine" the value for isForced is to introduce an input property to the component i.e.
#Input() isForced: boolean;
and invoke the component from elsewhere like:
<app-user [isForced]="true"></app-user>
You can use inputs.Write a component which takes input, and render it in html. then call this component in desired places with its selector
For events use output
See the doc https://angular.io/guide/inputs-outputs
I would like to create dynamically 3 input tags in Angular 6 to not copy/paste html code because that input elements have similar html and functionality.
For this purpose I created an array "reusableItems" inside component and initialize it :
let numberOfInputElements = 3;
for (let i = 0; i < numberOfInputElements; i++) {
this.reusableItems.push({
answer: 'Answer ' + (i +1),
passwordRecoveryAnswer: this.user['passwordRecoveryAnswer' + (i + 1)]
});
}
Then I put code inside my html :
<div *ngFor="let item of dropDownDataManagerService.reusableItems" >
<li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
<div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
<div class="col-xs-8">
<input type="text" name={{item.answer}} ref-{{item.answer}}="ngModel" class="col-sm-12 k-textbox ph0"
[(ngModel)]=item.passwordRecoveryAnswer
[pattern]="[a-z]"
required autocomplete="off"/>
</div>
</li>
</div>
It seems works fine but then I need to add error messages when these fields will be empty and not match to pattern. Something like :
<div *ngIf="__{{item.answer}}__.errors?.required ">
{{'Please provide an answer' | translate}}
</div>
<div *ngIf="__{{item.answer}}__.errors?.pattern">
{{'Pattern is not match'}}
</div>
I don't know what should i put inside ngIf condition.
How can I do it if my template reference variables are comes from array?
Is anyone have ideas?
Thanks
Angular creates unique template reference variable for each embedded template so that you can use the same template reference variable name inside ngFor loop:
<div *ngFor="let item of reusableItems">
<li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
<div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
<div class="col-xs-8">
<input type="text" name={{item.answer}} ref-answer="ngModel" class="col-sm-12 k-textbox ph0" [(ngModel)]="item.passwordRecoveryAnswer"
[pattern]="'[a-z]'" required autocomplete="off" />
<div *ngIf="answer.errors?.required">
{{'Please provide an answer'}}
</div>
<div *ngIf="answer.errors?.pattern">
{{'Pattern is not match'}}
</div>
</div>
</li>
</div>
In the code above I use the same name for each input in array
ref-answer="ngModel" // or you can also use #answer="ngModel
I have a problem with sending values from one component to other. I've got 2 components: report-form and comment-form. Report form have an array of comments. It also show list of comment and button for each of them. After clicking a button It should load modal form with #Input property commentIndex. Problem is that report-form component don't send only(!) first value of array to comment-form. I don't have idea why :/.
Here's some code:
Part of report-form.html:
<div class="form-group row">
<div class="col-md-12 alert alert-dark">Komentarze:</div>
<div class="col-md-12" *ngFor="let comment of comments">{{ comment.content }}
<app-comment-form [commentIndex]="comments.indexOf(comment)"></app-comment-form>
</div>
<br>
<app-comment-form></app-comment-form>
</div>
If I log it on console in comment-form I've got 1,2 in 3 elements array but where's 0?!
You can use index provided by the *ngFor directly.
<div class="form-group row">
<div class="col-md-12 alert alert-dark">Komentarze:</div>
<div class="col-md-12" *ngFor="let comment of comments; let i = index">{{ comment.content }}
<app-comment-form [commentIndex]="i"></app-comment-form>
</div>
<br>
<app-comment-form></app-comment-form>
</div>
This index will start from 0.
I have two divs - the first contains the second. The contained div has its own controller. When I click an icon button in the container, I change a variable which then affects the visibility of the contained div.
It looks like this:
<div ng-controller="BarController">
<div class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="col-lg-2 page-title">My Page</div>
<div class="col-lg-10">
<span class="actions">
<i class="fa fa-lg fa-download fa-inverse" tooltip="Download"
ng-click="showSecondaryBar=!showSecondaryBar"></i>
</span>
</div>
</div>
</div>
<div class="download navbar download-in download-out"
ng-class="{'myhidden': !showSecondaryBar}"
ng-cloak>
<div class="col-lg-offset-4 col-lg-4 form-inline form-group" ng-controller="TagsController">
<div class="download-label col-lg-6">
<label>Download by tags:</label>
</div>
<div class="download-tags col-lg-6">
<tags-input class="bootstrap" spellcheck="false" min-length="1" ng-model="tags" add-from-autocomplete-only="true">
<auto-complete source="loadTags($query)" min-length="1" load-on-down-arrow="true"
load-on-focus="true" max-results-to-show="5"
highlight-matched-text="false"></auto-complete>
</tags-input>
</div>
</div>
</div>
</div>
The <tags-input> is taken from ng-tags-input and I would like to reset the tags that were already typed to it whenever the icon button is clicked (which changes the visilibyt of the div that contains the ng-tags-input).
Problem is, because I have the TagsController which contains the data (tags) and this data is not visible in the BarController, I'm not sure how I can reset the tags array to become empty.
I thought of using a service but it fills like too much of a coupling. I would prefer to have a function in TagsController which is called upon click. But I can't figure out how to do it from another controller
You are right you have to use a service.
Why don't you use a broadcast as your TagsController is included in BarController?
You can include a scope.broadcast("Event") in BarController
Then a "on" listener on TagsController who will reset the tags array when "Event" Occur.
I would personnaly to this.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
You can use $broadcast on $rootScope to send an event to TagsController. So TagsController can receive this event by registering an event listener for it. See following example.
Refer to $rootScope API docs
angular.module('app',[])
.controller('ParentController', function($rootScope) {
var parentCtrl = this;
parentCtrl.someFlag = true;
parentCtrl.changeFlag = function() {
parentCtrl.someFlag = !parentCtrl.somFlag;
$rootScope.$broadcast('resettags', {'defaultTags': 'whatever_tag'});
}
})
.controller('ChildController', function($rootScope){
var childCtrl = this;
childCtrl.tags = "Some tags entered by user";
$rootScope.$on('resettags', function(event, args) {
childCtrl.tags = args.defaultTags;
});
});
.myHidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div id="main" ng-controller="ParentController as parentCtrl">
<button type="button" ng-click="parentCtrl.changeFlag()">Toggle</button>
<div ng-class="{'myHidden' : !parentCtrl.someFlag}">
<div ng-controller="ChildController as childCtrl">
<h1>{{childCtrl.tags}}</h1>
</div>
</div>
</div>
</div>