I'm having a logic error with my code using angular js. What I have done is made a function that loops through a json array and returns the strings of the weather condition, eg
'clear',
'cloudy', etc...
It then checks to see if the value of the string is equal to another string. If it is, it returns an image link associated with the weather condition. The problem is that html ng-repeat function is repeating that one image and not any other image.
Here is the js:
var app=angular.module('app');
app.controller('MainCtrl', function($scope, $http) {
$scope.currentSydney = null;
$scope.currentMelbourne = null;
$scope.currentAdelaide = null;
$scope.currentDarwin = null;
$scope.currentBrisbane = null;
$scope.currentMelbourne = null;
$scope.currentCairns = null;
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Melbourne.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentMelbourne=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Sydney.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentSydney=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Adelaide.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentAdelaide=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Darwin.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentDarwin=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Perth.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentPerth=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Cairns.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentCairns=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Brisbane.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentBrisbane=data;
$scope.cityData=[
{ name:'Brisbane',
temp:$scope.currentBrisbane.current_observation.temp_c,
image:$scope.currentBrisbane.current_observation.icon
},
{ name:'Melbourne',
temp:$scope.currentMelbourne.current_observation.temp_c,
image:$scope.currentMelbourne.current_observation.icon
},
{
name:'Adelaide',
temp:$scope.currentAdelaide.current_observation.temp_c ,
image:$scope.currentAdelaide.current_observation.icon
},
{ name:'Darwin',
temp:$scope.currentDarwin.current_observation.temp_c ,
image:$scope.currentDarwin.current_observation.icon
},
{ name:'Perth',
temp:$scope.currentPerth.current_observation.temp_c ,
image:$scope.currentPerth.current_observation.icon
},
{ name:'Cairns',
temp:$scope.currentCairns.current_observation.temp_c,
image:$scope.currentCairns.current_observation.icon
},
]
for(y = 0 ; y < 6; y++){
var string = $scope.cityData[y].image;
console.log(string[10]);
}
});
$scope.iconString = function() {
switch ($scope.currentSydney.current_observation.icon) {
case 'partlycloudy' :
return 'pics/partlycloudy.png';
case 'clear' :
return 'pics/partlycloudy.png';
}
}
$scope.repeat = function() {
for(y = 0 ; y < 1; y++){
var string = $scope.cityData[y].image;
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
}
});
And here is the html:
<div id="weather-container">
<div id="current-weather">
<!--Angular JSON pull -->
<div id="title"><span id="current-title">Current Weather</span></div>
<div id="current-condition">{{currentSydney.current_observation.weather}}</div>
<img ng-src="{{iconString()}}"></img>
<div id="current-temp"><span id="current-temp"> {{currentSydney.current_observation.temp_c}} </span></div>
<span id="current-city">{{currentSydney.current_observation.display_location.city}} </span>
</div>
<!--Angular JSON pull and iteration-->
<div id="other-city-container">
<div class="other-city-weather" ng-repeat="city in cityData" >
<!--Image-->
<img ng-src="{{repeat()}}"></img>
<div class="current-city-temp">
<span>{{city.temp}}</span>
</div>
<div class="current-city-lower">
<span>{{city.name}}</span>
</div>
</div>
</div>
</div>
Now I'm calling the repeat function in the html inside the img src tag.
`
I see. You are making 2 loops : ng-repeat in the view, and a for loop in the controller ( repeat() ).
But I think that right now, they are not related to each other (which is what you need I guess): getting the index of the ng-repeat loop in your repeat method.
Try something like that :
In the view :
<img ng-src="{{repeat($index)}}" /><!-- Getting the current $index of the ng-repeat loop and passing it to the $scope.repeat() method -->
In the controller :
$scope.repeat = function(index) { // there, index becomes the value we just put in the view ($index = the current index of the ng-repeat loop), e.g. : 0,1,2,3...
var string = $scope.cityData[index].image; // We go get the right city in the cityData array, according to the current ng-repeat index.
// then we do the job
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
Not sure that works as I didn't test it, but you may know what I mean ?
Related
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.
#Context
$scope.getAllEvents() is getting an array from Firebase database within the 10 last events and put it in the $scope.events array. Then the function is sorting by date $scope.events. I'm initializing $scope.spliceTab and calling $scope.spliceFunc().
$scope.counterPub() is triggered in HTML each time the ng-repeat $index is a multiple of 5. The function is storing in $scope.spliceTab each values of the $index which were triggered. Basically it's a tab where future new items locations are registered. Then i delete doubles and save results in $scope.result.
Finally, $scope.spliceFunc() is reading inside $scope.result, and insert into $scope.events new items where positions are stored into $scope.result.
#Running
At the start of my app, $scope.events is filled up but $scope.result from $scope.spliceFunc() stays empty. When I'm using the infinite scroll to load 10 more events, it is working but the $scope.events.sort() algorithm is working before $scope.spliceFunc(), so my new items are on the bottom of my list and not in the positions I want.
#Problem
I would like to run my app this way:
filled up $scope.events from Firebase
Sort $scope.events by date
ng-repeat in HTML and filled up $scope.spliceTab when triggered
Finally running $scope.spliceFunc() on the already sorted array $scope.events
What do you think, is this possible ?
// FUNCTION TO GET EVENTS
$scope.getAllEvents = function() {
if ($scope.listSiz === undefined) {
$scope.listSiz = 10;
}
var ref = firebase.database().ref().child("events");
$scope.events = $firebaseArray(ref.orderByChild('endDate').limitToFirst($scope.listSiz));
$scope.events.$loaded().then(function()
{
$scope.events.sort(function compareNumbers(y, x) {
var date1 = new Date(x.endDate);
var date2 = new Date(y.endDate);
return date1 - date2;
});
if ($scope.listSiz === 30) {
$scope.noMoreItemsAvailable = true;
}
$scope.spliceTab = [];
$scope.spliceFunc();
});
};
// FUNCTION TRIGGERED IN HTML
$scope.counterPub = function($index) {
var modulo = $index % 5;
if (modulo === 0) {
$scope.spliceTab.push($index);
// Delete doubles
$scope.result = [];
$scope.spliceTab.forEach(function(item) {
if ($scope.result.indexOf(item) < 0) {
$scope.result.push(item);
}
});
return true;
} else {
return false;
}
};
// FUNCTION SPLICE
$scope.spliceFunc = function() {
// console.log("************* TAB ****************** =", $scope.result);
angular.forEach($scope.result, function(value) {
$scope.events.splice(value, 0, [{
name: "toto"
}]);
});
};
<ion-view>
<ion-content>
<ion-list ng-controller="MCtrl">
<ion-item ng-repeat="e in events">
<!-- IF ADDS -->
<div ng-if="counterPub($index) === true">
Hello world !
</div>
<!-- -->
<div>
<img data-ng-src="{{ ::e.creatorAvatar }}">
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
I am developing application in which I have feeds or some timeline. here is my ng-repeat code:
<div ng-repeat="x in feeds" class="fd-feed-card">
<div class="fd-feed-usr-img">
<img ng-src="{{x.user.media[0].small}}" class="fd-img fd-img-br border-style">
</div>
<div class="ft-16 fd-feed-usr-name">
<span><b>{{x.user.name}}</b></span><span class="ft-12 fd-feed-created-time plx prm">{{x.feed.createdTimeStamp | readableTime}}</span>
</div>
<div ng-style="imgStyle">
<img ng-src="{{x.feed.media[0].medium}}" class="fd-img objectcover image-blur">
</div>
<div ng-if="x.feed.total_comments > 0 || x.feed.total_likes >0">
<p class="mll"><span on-tap="openCommentModal(x.feed._id, $index, x.feed)" class="prm" ng-if="x.feed.total_comments > 0">{{x.feed.total_comments}} Comment</span><span ng-if="x.feed.total_likes>0" on-tap="openUserModal(x.feed._id)">{{x.feed.total_likes}} Likes</span>
</p>
</div>
<div class="fd-feed-distance">
<span class="plx prm ft-16">{{x.distance}} <span class="ft-10">mil</span></span>
</div>
</div>
here every feed contains username, userimage and 400*400px image of feed and distance. after this im using ionic infinite scroll like this:
<ion-infinite-scroll on-infinite="getDashboardFeed()" distance="1%" ng-if="!noMoreFeedContent"></ion-infinite-scroll>
in my javascript code, i am calling API with pagination having 5 feeds at a time. here it is my javascript code:
$scope.getDashboardFeed = function(start) {
var _start = start || false;
var params = {}
params.offset = offset;
params.limit = limit;
Posts.getAllFeeds(params).success(function(res) {
if (_start) {
$scope.feeds = [];
}
if (res.data.length < limit) {
$scope.noMoreFeedContent = true;
} else {
$scope.noMoreFeedContent = false;
}
for (var i = 0; i < res.data.length; i++) {
var markerPos = new google.maps.LatLng(res.data[i].feed.location[0], res.data[i].feed.location[1]);
var currentLatLng = new google.maps.LatLng(res.data[i].location.location[0], res.data[i].location.location[1])
var distance = google.maps.geometry.spherical.computeDistanceBetween(markerPos, currentLatLng) * 0.000621371;
res.data[i].distance = distance.toFixed(2);
for (var j = 0; j < res.data[i].feed.likes.length; j++) {
if (uid == res.data[i].feed.likes[j].user) {
res.data[i].isLiked = true;
break;
} else {
res.data[i].isLiked = false;
}
}
$scope.feeds.push(res.data[i]);
}
offset = offset + limit;
if (_start) {
$scope.$broadcast('scroll.refreshComplete');
} else {
$scope.$broadcast('scroll.infiniteScrollComplete');
}
})
.error(function(err) {
})
};
im also calculating distance of every feed based on current location. and checking if i liked the post or not.
Now the problem is when feed is loaded to 25,30 , the scroll becomes laggy in my android . Im also using native scrolling given in this link ,
i have read also more blogs like this
but i didnt get much help. I have to load 1000s of feeds here where every feed contains 400*400px picture.
i also tried collection-repeat. it didnot work either.
Is there any other approach I can try to fix my scroll perfomance?
Anybody can help me with that?
I had same issue, especially when using images in ng-repeat.
Check out my answer here
Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>
I have an array that I'm removing items from but I'm keeping count of the number of items to do UI formatting. I need to be able to have the bind update.
ko.applyBindings(viewModel);
getFoos();
var viewModel = {
foos: ko.observableArray([]),
reloadFoos: function () {
getFoos();
},
removeFoo: function () {
remove(this);
}
};
var foo = function () {
this.Id = ko.observable();
this.Name = ko.observable();
this.Count = ko.observable();
};
function remove(foo) {
viewModel.foos.splice(viewModel.foos.indexOf(foo), 1);
viewModel.foos.each(function(index) {
viewModel.foos[index].Count = index%10 == 0;
});
}
function getFoos() {
viewModel.foos([]);
$.get("/myroute/", "", function (data) {
for (var i = 0; i < data.length; i++) {
var f = new foo();
f.Id = data[i];
f.Name = data[i];
f.Count = i%10 == 0;
viewModel.foos.push(f);
}
});
}
<div data-bind="foreach: foos">
<div style="float: left">
<a href="javascript:void(0);" data-bind="click : $parent.removeFoo, attr: { id: Id }">
<label data-bind="value: Name"></label>
</a>
</div>
<!-- ko if: Count -->
<div style="clear: left"></div>
<!-- /ko -->
</div>
When the click event fires the item is removed from the array but the if bind doesn't get updated and the ui formatting is off. I'm trying to keep from reloading the data because the ui block bounces as it removes and reloads.
Your UI is not being updated because when you do your assignment to Count, you aren't assigning as an observable. You are replacing the observable with a straight boolean value. So, your assignment calls like this one:
viewModel.foos[index].Count = index%10 == 0;
Will cause viewModel.foos[index].Count to be equal to true or false and the value won't be stored in the observable.
That line should be this instead:
viewModel.foos[index].Count(index%10 == 0);
That will set the observable correctly. Note that you must change all of your assignments to observables to be set this way. See the "Reading and Writing Observables" section of this page: Knockout Observables.