Passing data between components and use the ngDocheck - javascript

We are trying to pass data from one component to another and below is the approach we are taking. When there is no data we want to show the error message and if there is data we show that in the select box.
showGlobalError = true;
constructor(
private psService: ProjectShipmentService,
private pdComp: ProjectDetailsComponent
) {
this.psService.tDate.subscribe(x => this.cachedResults = x);
}
ngOnInit() { }
ngDoCheck() {
if (this.cachedResults.length > 0 && this.count <= 1) {
this.showGlobalError = false;
this.populateArrays();
this.count++;
}
}
populateArrays() {
this.reportingProject = [this.pdComp.rProjectNumber];
this.projectSalesOrder = this.pdComp.rSalesOrder;
this.clearFilter();
// ........
Our HTML looks like below:
<div *ngIf="showGlobalError">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
<div id="search-block" class="box-shadow-block">
<span>Reporting Project</span>
<dx-select-box
[items]="reportingProject"
[text]="reportingProject"
[readOnly]="true"
>
</dx-select-box>
</div>
The issue is The Reporting Project number appears in the select box but when I click on the select box and click anywhere else in the page the project number disappears. I am not sure if this has something to do with the ngDoCheck(). Any help is greatly appreciated

set first your showGlobalError to false and do the logic in your ngOnInit.
showGlobalError = false;
in your view:
<div *ngIf="showGlobalError">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
<div *ngIf="!showGlobalError" id="search-block" class="box-shadow-block">
<span>Reporting Project</span>
<dx-select-box
[items]="reportingProject"
[text]="reportingProject"
[readOnly]="true"
>
</dx-select-box>
</div>

use following code to get data from service.
this.psService.tDate.subscribe(x => {this.cachedResults = x},
(err) => {},
() => {this.checkForCachedResults()}
);
and write function to execute your conditional check instead of doCheck() like follows
checkForCachedResults() {
if (this.cachedResults.length > 0 && this.count <= 1) {
this.showGlobalError = false;
this.populateArrays();
this.count++;
}
}

Related

Im trying to pass array as arguments to httpservice call, but the argumments is evaluating to empty array

Im trying to upload multiple images, hence converting the image to a base64 encoded string and also storing its metadata with an array.We store the reference to the image path to database hence functionionality is written in backend for insertion.
However ,
To process image files into base64 and store metadata i use array and trying to pass as arguments to a function but i receive empty array in service call. Could someone help me understand why and how to fix this.
the upload image is called for every iteration of for loop , WHY?
Thanks in advance .
export class ItemsDetailsComponent {
//image variables
itemImageDetails: any = [];
ItemImageURLs: any = [];
itemImageCount: number = 0;
base64image: any = [];
CustImageData: any;
itemImageData: any;
itemimagePath: any;
fileList: any = [];
newImageMetaData: any = [];
imageMetaData: any = [];
addImagePopupVisible: boolean = false;
deleteImagePopupVisible: boolean = false;
tempImageCount: number = 0;
deleteImageURL: any;
deleteImageName: any;
deleteImageConfirmPopUp: boolean;
value: any[] = [];
constructor() {
// ...
}
processFile() {
let count = 0;
for (let i = 0; i < this.value.length;
(i++, count++)) {
this.fileList.push(this.value[count]);
this.httpDataService.getBase64(this.value[count])
.then(base64img => {
this.base64image[this.tempImageCount] = base64img;
this.base64image[this.tempImageCount] = this.base64image[this.tempImageCount].split(",")[1];
this.tempImageCount++;
this.newImageMetaData.push({
"type": this.fileList[i].type,
"name": this.fileList[i].name,
"size": this.fileList[i].size
});
});
}
//want to call this function only after for loop is complete but is getting called at every iteration , WHY?
this.uploadImages();
}
uploadImages() {
if (this.newImageMetaData.length == this.base64image.length) {
//recieves expected output(the array in log) **
console.log(this.newImageMetaData);
console.log(this.base64image); **
// below service call is receiving empty array - >> [] for ** [...this.base64image] ** ** [...this.newImageMetaData] **
this.httpDataService.uploadMultipleImages(["", this.itemCode, [...this.base64image],
[...this.newImageMetaData]
])
.subscribe(status => {
if ((status != -1) && status) {
this.toastr.success(status + "Image(s) Successfully Uploaded");
this.getImag();
this.getItemImageDetails();
this.newImageMetaData = [];
this.base64image = [];
} else {
this.toastr.error("Error Uploading image" + status + " Image(s) Uploaded ");
}
this.addImagePopupVisible = false;
});
}
}
//
<div class="widget-container">
<form enctype="multipart/form-data">
<dx-file-uploader #fileUploader [multiple]="true" accept="image/*" [(value)]="value" uploadMode="useForm"></dx-file-uploader>
<div class="content">
<div *ngIf="value.length > 0">
<h4>Selected Files</h4>
</div>
<div *ngFor="let file of value">
<div class="selected-item">
Name:
<span>{{file.name}}</span><br /> Size:
<span>{{file.size}}</span>bytes<br /> Type:
<span>{{file.type}}</span><br /> Last Modified Date:
<span>{{file.lastModifiedDate}}</span>
</div>
</div>
</div>
<dx-button text="Create Product" type="submit" (onClick)="uploadImages()">
</dx-button>
</form>
</div>
<div class="options">
<div class="caption">Options</div>
<div class="option">
<dx-check-box text="Allow multiple files selection" [(value)]="fileUploader.multiple"></dx-check-box>
</div>
</div>
Assuming that dx-button is a Call To Action, try and remove the action="uploadImages()" from the form tag, eventually, it will be called once processFile() completes the iteration.
If you keep an action as well as the submit button inside a form the button click will get performed.
OR
Remove onClick from button and replace uploadImages() with processFile() in form tag.

Component in Angular on click it is taking whole arrays as selected not only once

I am implementing a rating component in Angular, which I'll use in another component to rate the language.
Rate I mean how good is with it.
My problem it is that when I do hear a click event for one array, automatically will select the second array and give them both or will fill both of them with color.
It is possible to click only one event and give it data.
The code for star component I am based in this stackblitz.
https://stackblitz.com/edit/angular-material-star-rating-kptyy2?file=app%2Fapp%2Fapp.component.html
Here is my star component.
<button mat-icon-button *ngFor="let ratingId of ratingArr;index as i" [id]="'star_'+i" (click)="onClick(i+1)"
>
<mat-icon>
{{showIcon(i)}}
</mat-icon>
</button>
<mat-error *ngIf="starCount == null || starCount == 0">
</mat-error>
export class StarRatingComponent implements OnInit {
#Input("rating") private rating = 3;
#Input("starCount") public starCount = 5;
#Output() private ratingUpdated = new EventEmitter();
public ratingArr = [];
constructor() {
}
ngOnInit() {
for (let index = 0; index < this.starCount; index++) {
this.ratingArr.push(index);
}
}
onClick(rating: number) {
this.ratingUpdated.emit(rating);
return false;
}
showIcon(index: number) {
if (this.rating >= index + 1) {
return "star";
} else {
return "star_border";
}
}
}
And this is the component which I try to show it and fill with data.
<div *ngFor="let language of subCategory.languages; let i = index">
<div class="col-md-8">
{{language.name}}
<app-star-rating [rating]="language.rate" [starCount]="starCount" (ratingUpdated)="onRatingChanged($event)"></app-star-rating>
</div>
</div>
onRatingChanged(rating) {
this.skills.subCategories.map(test => test.languages.filter(res => {
console.log(res.name);
res.rate = rating;
}));
}
You can pass the index from the HTML in the onRatingChanged function along with event as below:
<div *ngFor="let language of languages; let i = index">
<div class="col-md-8">
{{language.name}}
<mat-star-rating [rating]="language.rate" [color]="starColor" (ratingUpdated)="onRatingChanged($event,i)"></mat-star-rating>
</div>
</div>

how to handle the multiple ng-show and one ng-hide in angularjs if one condition is set to true and the left out ng-show to be false

When a user hovers over the stars, I want to show the message You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a>, and if the user has clicked on the rating I want to show 'Thanks for rating' (see html below for my logic). But after this if the user hovers again over the stars I want to show You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a> again.
Issue is once rated, it shows 'Thanks for rating' always. How to fix this?
Please see my attempt at doing this below, and it would be helpful if someone can point out the error I have made. Thanks!
<div class="user">
<uib-rating ng-model="rate" max="5" read-only="isReadonly" on-titles="['one','two','three']" aria-labelledby="default-rating" class="readOnlyRating "></uib-rating>
<div class=" arrow_box rt" ng-show="showRatings">
<div class="ratingName">
<h5><b>Give your rating here..</b></h5>
</div>
<div class="stars">
<uib-rating ng-model="rate1" ng-click="rating(rate1)" max="5" read-only="isReadonly1" on-hover="hoveringOver(value)" on-leave="overStar = null" titles="['one','two','three']" aria-labelledby="default-rating" class="readOnlyRating "></uib-rating>
</div>
</div>
<div ng-mouseleave="hoverOut()" class="arrow_box rt" ng-show="ratevalue ">
<h5 class="ratedPopover"> Thanks for rating </h5>
</div>
<div class="arrow_box rt" ng-hide="showRatings">
<h5 class="ratedPopover">You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a>
</h5>
</div>
</div>
here is my directive file
scope.rating = function (rate) {
scope.ratevalue = rate;
if ($localStorage[localStorageRatingKey] == undefined) {
previousRatingValue = 0;
$localStorage[localStorageRatingKey] = scope.ratevalue;
} else {
previousRatingValue = $localStorage[localStorageRatingKey];
$localStorage[localStorageRatingKey] = scope.ratevalue;
}
ratingService.update({
companyId : scope.details._id,
userRating : scope.ratevalue,
previousRatingValue : previousRatingValue
}, scope.details, successCallback, errorCallback);
function successCallback(res) {
// console.log("coming from callback");
scope.rate = res.avgRatings;
scope.reviewsCount = res.totalRatingsCount;
}
function errorCallback(res) {
NotificationFactory.error('Failed to update the product rating...', res.data.message);
}
};
scope.showMe = function () {
scope.showRatings = !scope.showRatings;
console.log("showme :" + scope.showRatings);
}
scope.hoverOut = function () {
if ($localStorage[localStorageRatingKey]) {
scope.showRatings = !scope.showRatings;
} else {
scope.showRatings = true;
}
console.log("hoverOut ShowRatings:" + scope.showRatings);
}
if ($localStorage[localStorageRatingKey]) {
scope.showRatings = false;
} else {
scope.showRatings = true;
}
Instead of using ratevalue to show the message 'Thanks for rating', I would suggest using a flag like hasjustRated. In your code initialize this to false
at the beginning of this function definition: scope.rating = function (rate) { ... }
Also at the end of the success callback, add the following lines:
scope.hasjustRated = true;
Then on leave of hover, reset this value to false. I suggest adding a clear function for on leave that would do all the necessary steps when leaving hover.
Also what the showMe function does is a bit unclear.

How to avoid rendering element as simple as possible

I have a reactJS component that looks like this :
var LikeCon = React.createClass({
render(){
return this.renderLikeButton(this.props.like, this.props.likeCount)
},
renderLikeButton(like, likeCount){
var content;
var tmpLikeCount;
if(likeCount < 1){
tmpLikeCount = "";
}
else{
tmpLikeCount = likeCount;
}
if(like == 1){
content = <div className="likeButConAct"><div className="likeB"> </div><div className="likeCount">{tmpLikeCount}</div></div>
}
else{
content = <div className="likeButCon"><div className="likeB"> </div><div className="likeCount">{tmpLikeCount}</div></div>
}
return content;
}
});
Say that I want to hide the likeCount element if there is no likes. How do I do this as simple as possible? I donĀ“t want another component to render this.
If your variable is null or undefined then React simply won't render it. That means your conditional code can be as simple as:
var tmpLikeCount;
if(likeCount >= 1){
tmpLikeCount = likeCount;
}
But I think you can make your code even simpler using class sets:
http://facebook.github.io/react/docs/class-name-manipulation.html
var LikeCon = React.createClass({
render(){
var likeCountCmp;
var classes = React.addons.classSet({
likeButCon: true,
active: this.props.like
});
if(this.props.likeCount > 0) {
likeCountCmp = <div className="likeCount">{this.props.likeCount}</div>;
}
return (
<div className={classes}>
<div className="likeB"> </div>
{likeCountCmp}
</div>
)
}
});
A final variation that I think will work is to use an implicit function return:
var LikeCon = React.createClass({
render(){
var classes = React.addons.classSet({
likeButCon: true,
active: this.props.like
});
return (
<div className={classes}>
<div className="likeB"> </div>
{this.getLikeCountCmp()}
</div>
)
},
getLikeCountCmp: function() {
if(this.props.likeCount > 0) {
return <div className="likeCount">{this.props.likeCount}</div>;
}
}
});
if we don't specifically return anything from getLikeCountCmp, we end up with undefined, which React renders as nothing.
Note that I'm a bit confused with your like == 1 comparison - should that be true/false rather than a number? I've assumed this.props.like will be true or false in my examples. That means it'd be called with:
<LikeCon like={true|false} likeCount={5} />
If you like to put everything inline, you can do this:
renderLikeButton(like, likeCount){
return (<div className={like==1 ? "likeButConAct" : "likeButCon" }>
<div className="likeB"> </div>
{ likeCount > 0 ? <div className="likeCount">{likeCount}</div>: null }
</div>);
}
That way you wont be rendering .likeCount div if likeCount is 0.
jsFiddle: http://jsfiddle.net/715u9uvb/
what about using the className to hide the element?
something like :
var cssClasses = "likeButConAct ";
if ( likeCount < 1 ) {
cssClasses += "hidden";
}
...
return <div className=cssClasses><div ...
EDIT
var content;
var tmpLikeCount;
var likeCounterComponent;
if(likeCount > 0){
likeCounterComponent = <div className="likeCount">{likeCount}</div>
}
if(like == 1){
cssClasses = "likeButConAct"
}
else{
cssClasses = "likeButCon";
}
return (
<div className=cssClasses>
<div className="likeB"> </div>
{ likeCounterComponent }
</div>);
You can add the likeCounter only if there are likes. If there are likes the likeCounterComponent contains the JSX code to render the likes counter, otherwise is undefined and therefore nothing will be rendered.
I haven't tried to run the code, but I guess you got the idea to solve this problem. :D
Colin's answer looks good to me.. if your issue is with having aspects of rendering extracted to a separate function, you don't HAVE to do that. This works too:
return (
<div className={classes}>
<div className="likeB"> </div>
{this.props.likeCount > 0 && (
<div className="likeCount">{this.props.likeCount}</div>
)};
</div>
)
....
if (likeCount < 1) {
return "";
}
....

angularjs-how to implement click in angular

I am a newbie in angularjs.
I was stuck on a code and wanted some help.
I am having a controller called watchlist controller in which I am getting the data which is to be displayed in the watchlist.
However I want to display the data only once the watchlist tab is clicked.
This is the Html code :-
<div class='watchlist' >
<button class='btn' id="watchList" ng-click="fetchUserWatchlist()" watchlist-popover ng-controller="WatchlistController">
<i class="hidden-tablet hidden-phone"></i>
<span class = 'mywatchlist'>My Watchlist</span>
<div class = 'watchlist-spinner ' ></div>
</button>
</div>
My controller(watchlist):-
$scope.fetchUserWatchlist = function(pageno,callback){
$scope.isLoading = true;
$rootScope.isrequest = true;
userAPI.myWatchlist({userid:$rootScope.getUser().userid,pageno:pageno}, function(r) {
if (_.isNull(r.watchlistdata)) {
if(typeof callback == 'function'){
callback();
}
if(pageno == 1){
$scope.watchlist = [];
$scope.watchlistCount = 0;
}
if (!$rootScope.apiCalled && pageno == 1){
if(!_.isUndefined($rootScope.watchlistClicked) && $rootScope.watchlistClicked){
$rootScope.$broadcast("watchlist::click");
imageLoadingIndicator();
}
$rootScope.apiCalled = true;
}
return false;
}
if (!_.isUndefined(r.watchlistdata.watchlist)){
var rawData = [];
var tempWatchlist = $scope.watchlist;
if (_.isArray(r.watchlistdata.watchlist))
rawData = r.watchlistdata.watchlist;
else
rawData = [r.watchlistdata.watchlist];
if (pageno == 1) {
$scope.watchlistCount = parseInt(rawData[0].totalcount);
}
if ($scope.watchlist.length == 0 || ($scope.watchlist.length > 0 && pageno == 1))
$scope.watchlist = rawData;
else
_.each(sortByDate(rawData),function(item){
if (! _.some(tempWatchlist,function(existingItem){ return existingItem.programmeid == item.programmeid; }))
{
$scope.watchlist.push(item);
}
});
$scope.watchlistPage += 1;
$timeout(function(){
if (!$rootScope.apiCalled && pageno == 1){
if(!_.isUndefined($rootScope.watchlistClicked) && $rootScope.watchlistClicked){
$rootScope.$broadcast("watchlist::click");
imageLoadingIndicator();
}
$rootScope.apiCalled = true;
}
},1);
$rootScope.isrequest = false;
if(typeof callback == 'function'){
callback();
}
}else
$rootScope.end = true;
});
};
So basically I want to implement ng-click on the controller but here in the above scenario it does not help..The data is called before the button is clicked.
Please help me with this
ng-click will work using the scope:
ng-click="executeThis()"
will look in the $scope for a variable named 'executeThis'. F.e.:
$scope.executeThis = function(){
// Do stuff you want
};
So when you click the element that has this ng-click attribute, the executeThis function on the scope will be executed. In this function you should do whatever you want to do. To display something when you click it, you could use the function to set a variable on the scope to true and then use ng-show to display what you want to display.
HTML:
<div ng-show="varX">someDiv</div>
JS inside controller:
$scope.varX = false;
So whenever you set this variable to true, your element should be shown.
However, I do suggest following some tutorials since I suspect you don't yet grasp how angular works.. Understanding how the fundamentals of angular work is definitely necessary if you want to develop an app.
try
<button class='btn' id="watchList" ng-click="myClickFunction()" watchlist-popover ng-controller="WatchlistController">
The best way to learn (IMHO) is documentation :-)

Categories

Resources