Updating a single item in angular scope object - angularjs

I am creating a like function for pictures on an Ionic app.
I can return a like count and true or false for if the request was to like or unlike a photo.
I have a function on my photos which calls a post action in my controller (the on double tap)
<div ng-repeat="update in updates" class="custom-card">
<div ng-show="{{update.image}}" class="image">
<img on-double-tap="likeUpdate({{update.data.id}})" class="full-image" ng-src="https://s3-eu-west-1.amazonaws.com/buildsanctuary/images/{{update.image.name}}" imageonload>
</div>
<div class="action-bar">
<div class="left">
<i ng-class="liked ? 'ion-ios-heart red' : 'ion-ios-heart-outline'"></i><span>like</span>
</div>
</div>
If this was a single update shown, I would simple update the 'update' scope and it would work. But I have a list of photo's shown and the user can double tap on anyone. What I need is to be able to update the scope of updates but only for a single update and not the whole lot.
My function in controller:
$scope.likeUpdate = function(update_id) {
console.log("clicked");
$http.post( $rootScope.apiURL + 'likeupdate', {
update_id : update_id,
user_id : $rootScope.currentUser.id
}).success(function(update, response){
// update the specific ng repeat item scope?
});
}
Is there an angular way for this?

Don't pass the id, pass the whole update into your handler so you can change it inside, something like this:
<img on-double-tap="likeUpdate({{update}})" ... >
And controller:
$scope.likeUpdate = function(update) {
console.log("clicked");
$http.post( $rootScope.apiURL + 'likeupdate', {
update_id : update.data.id,
user_id : $rootScope.currentUser.id
}).success(function(result, response){
update.xxx = ...
});
}
A simple runnable example:
angular.module('myApp', [])
.controller('MyController', ['$scope', function($scope) {
$scope.updates = [{'name':'one', count: 2}, {'name':'two', count:3}];
$scope.likeUpdate = function(update) {
// this doesn't work:
update = {'name': 'test', count: update.count+1};
// this works:
update.name = 'test';
update.count += 1;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<div ng-repeat="update in updates" class="custom-card">
<div ng-click="likeUpdate(update)">{{update.name}} - {{update.count}}</div>
</div>
</div>

Related

Setting $location and then filtering with AngularJS

For the purposes of navigation, I'm trying to have a button that triggers a function.
This function must first:
-Redirect to #/
And then:
-Filter an ng-repeat that exists in this view.
This is what I've tried but no luck.
<li><a ng-click="shopsingle()">Shop</a></li>
And JS:
$scope.shopsingle = function(){
$location.path("/");
setTimeout(function () {
$scope.$apply(function(){
$scope.filterExpr = {"shop" : true};
console.log($scope.filterExpr);
});
}, 300);
};
It does redirect to the desired path, where a full ng-repeat list appears, but it won't apply the filter, and console also comes empty.
About the views and routing, I'm using the same template for 2 different views, and showing/hidding parts of if while watching the $routeParams:
.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "home.htm",
controller : "mainCtrl"
})
.when('/:name',
{
templateUrl:"home.htm",
controller:"mainCtrl"
})
.otherwise({redirectTo:'/'});
})
And the controller watch:
$scope.name = $routeParams.name;
$scope.$watch(function() { return $scope.name; }, function(newVal) {
if (!newVal){
$scope.single = false;
} else{
$scope.single = true
};
$scope.newname = newVal;
$scope.chosenexhibitor = $filter("filter")($scope.images, {'name':$scope.newname}, true);
}, true);
And the view:
<!-- MAIN PAGE -->
<div ng-hide="single" id="tiles" masonry='{ "transitionDuration" : "0.15s" , "itemSelector" : ".tile"}'>
<div masonry-tile ng-repeat="item in images | filter:filterExpr" class="tile col-xs-3 col-md-3">
<a href="#/{{item.name}}">
<img class="img-fluid" ng-src="img/{{item.link}}">
</a>
</div>
</div>
<!-- SINGLE PAGE -->
<div class="row flexing" ng-show="single">
<div class="col-md-12">
<h1>{{chosenexhibitor[0].name}}</h1>
<img ng-src="img/{{chosenexhibitor[0].link}}">
<a class="back" href="#/">Back</a>
</div>
</div>
What am I missing?

Angular returns [object Object]

my Angular code returns [object Object]. I am calling 2 controllers on different pages. First one sets the data on ng-click and the second one gets (displays) the data. Here is the code:
Angular App code:
var careerApp = angular.module("careerApp", []);
careerApp.factory('myService', function () {
var savedData = {};
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
careerApp.controller("JobList", function ($scope,myService) {
myService.set(data);
});
careerApp.controller("JobSelection", function ($scope, myService) {
$scope.jobname = myService.get();
});
HTML on Page 1
<div class="center-details" ng-controller="JobList">
<div class="details" ng-click="set(data)" >
<h2 class="name" ng-model="jobtitle">
Winter
</h2>
<p><b>Job ID#</b> <span class="jobid">2017-01</span></p>
</div>
</div>
HTML on Page 2
<div ng-controller="JobSelection">
<label ng-bind="jobname"></label>
</div>
You are bringing the whole object in
<label ng-bind="jobname"></label>
If you intented to write the object with a better formatting try changing it to:
<label> {{ jobname | json }}</label>
This way it will be formatted and printed as a json object.
Use Angular expressions intead of ng-bind. Otherwise you will have to specify a specific property of your object.
page 1
<div class="center-details" ng-controller="JobList">
<div class="details" ng-click="set('Winter')" >
<h2 class="name">
Winter
</h2>
<p><b>Job ID#</b> <span class="jobid">2017-01</span></p>
</div>
</div>
Controller:
careerApp.controller("JobList", function ($scope,myService) {
$scope.set= function(data){
myService.set(data);
}
});
page 2
<label ng-bind="jobname"></label>
<label>{{jobname}}</label>
How to make it dynamically, based on the input
<input stype="text" ng-model="jobTitle" ng-change="set()" >
<h2 class="name">
{{jobTitle}}
</h2>
Controller:
careerApp.controller("JobList", function ($scope,myService) {
$scope.jobTitle = "";
//This function will be called every time that jobTitle change its value.
$scope.set= function(){
myService.set($scope.jobTitle);
}
});
Notes:
Take into account that ng-model directive binds an input, select, textarea value to a property on the scope.
Since you have this assignment in your controller definition
$scope.jobname = myService.get();
If you run this controller before the user make a click it will be empty. it wont be refreshed in every click.

couldn't figure out the issue with angular routing / ng-repeat.

The aboutus.html page is displayed correctly, except the content in the ng-repeat within media-list in aboutus.html. there are no errors displayed in the console. I have not included the entire code (since it takes more space.). Can anyone help me?
// factory here.
angular.module('vasuapp')
.factory('corporateFactory', function() {
// Implement two functions, one named getLeaders,
// the other named getLeader(index)
// Remember this is a factory not a service
var corpfac = {};
var leadership = [
{
id: 0,
name:"asdfd",
designation:"sgsdgg",
abbr: "fgdfvf",
},
{
// similarly some other data here.
} ];
corpfac.getLeader = function(){
return leadership;
};
corpfac.getLeaders = function(index)
{
return leadership[index];
};
return corpfac;
});
// app.js
angular.module('vasuapp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider
.when('/aboutus', {templateUrl:'./aboutus.html' , controller: 'AboutController'})
.otherwise('/');
})
// controller.js
angular.module('vasuapp')
.controller ('AboutController',['$scope','corporateFactory', function($scope,corporateFactory){
var leadership = corporateFactory.getLeader();
$scope.leaders = this.leadership;
}])
// aboutus.html
<div class="row row-content">
<div class="col-xs-12 col-sm-9">
<h2>Corporate Leadership</h2>
<p> hi </p>
<ul class="media-list">
<li class = "media" ng-repeat = "lead in leaders">
<div class = "media-list tab-pane fade in active">
<a ng-href="#/aboutus">
<img class = "media-object" ng-src={{lead.image}} alt="author image">
</a>
</div>
<div class = "media-body">
<p>{{lead.description}}</p>
</div>
<footer>
-- {{lead.name}} the {{lead.designation}}
</footer>
</li>
</ul>
</div>
I think what you want is:
$scope.leaders = corporateFactory.getLeader();
this.leadership is not defined.

AngularJS: showing/hiding elements during UI update

I'm trying to solve an issue that's making my angular app look odd. I have an $http.get which initializes the model. Since it takes a couple of seconds to resolve against the server, I want to display an information tag until it's done.
However, what's happening is that the tag gets hidden before the rest of the UI is finished updating.
I've tried various approaches based on googling, but so far without success. Here's my current markup:
<div ng-controller="endCtrl" ng-show="model.groups.length > 0">
<div ng-repeat="group in model.groups" ng-show="group.Endorsements.length > 0">
<h3>{{group.Title}}</h3>
<div ng-repeat="endorsement in group.Endorsements">
<p>
<span class="endorsement-name">{{endorsement.Name}}</span><span class="footnote" ng-show="endorsement.Role != null">, {{endorsement.Role}}</span>
</p>
</div>
</div>
</div>
And here's the controller:
app.controller( '#ViewBag.AngularController', function( $scope, $http, $q, $timeout ) {
$scope.model = {
groups: [],
};
$http.get( "/Home/GetEndorsements" )
.then(
function( resp ) {
$scope.model.groups = resp.data;
return $q.defer().resolve( true );
},
function( resp ) {
$scope.model.groups = [];
return $q.defer().resolve( true );
}
)
.then( function( resp ) {
$timeout;
} )
} );
I included the call to $timeout because something I read suggested it would not run until the UI was finished updating. But again, that's not working.
Update
My problem was the result of a bone-headed mistake: the "please wait" element was outside the scope of the controller:
<p ng-show="model.groups.length <= 0">
Initializing, please wait...
</p>
<div ng-controller="endCtrl">
<div ng-show="model.groups.length > 0">
so, naturally, the ng-show directive on it always returned false, hiding the element as soon as it was compiled into the DOM.
Moving the item into the scope of the controller solved the problem.
You can see a plunker working like you want.
You should try a more "regular" way of using $http.
My Controller
$scope.model = {
groups: [],
gettingData: true,
};
$http.get( "data.json" )
.success(function(resp){
$scope.model.groups = resp.data;
$scope.model.gettingData = false;
}).error(function(resp) {
$scope.model.groups = [];
$scope.model.gettingData = false;
});
My view
<body ng-app="myApp" ng-controller="myController">
<span ng-show="model.gettingData">Loading !!!!!</span>
<div ng-show="!model.gettingData">
<div ng-repeat="group in model.groups" ng-show="group.Endorsements.length > 0">
<h3>{{group.Title}}</h3>
<div ng-repeat="endorsement in group.Endorsements">
<p>
<span class="endorsement-name">{{endorsement.Name}}</span><span class="footnote" ng-show="endorsement.Role != null">, {{endorsement.Role}}</span>
</p>
</div>
</div>
</div>
</body>
Tell me if it work as you expected. Actually your logic seems good, but i'm a bit confused with your way of using $http.

Controller triggered via factory

I am still a novice with angular. I have asked a question similar to this before, but it seems to be a different issue at work here.
I have two controllers and a factory sharing information between them. I have two separate divs using two different controllers to show / hide using ng=show;
HTML
<div id=main>
<div ng-controller="Ctrl1">
<div ng-show="var1">Hidden Stuff</div>
</div>
<div ng-controller="Ctrl2">
<div ng-show="var1">More Hidden Stuff</div>
</div>
</div>
Both use the same var for ng-show, shared by a factory
JS Factory
app.factory('Srvc', function($rootScope) {
var Srvc = {};
Srvc.var1;
return Srvc;
});
JS Controllers
app.controller('Ctrl1', function($scope, Srvc) {
$scope.var1 = false;
if (user interacts with html in div with ng-controller="Ctrl1") {
$scope.var1 = true;
Srve.var1 = $scope.var1;
}
});
app.controller('Ctrl2', function($scope, Srvc) {
$scope.var1 = Srvc.var1;
if ($scope.var1 === true) {
update HTML in div with ng-controller="Ctrl2"
although I shouldn't need to do this really should I?
}
});
So from what I can tell the factory works ok, the data is saved in the factory Srvc.var1. However when I pass the data true to Srvc.var1 I cannot seem to get Ctrl2 to 'trigger' and update its html with ng-show=true
One way to solve this problem without explicitly creating a watcher, is to wrap var1 in an object inside the service and then pass this object as a $scope variable for both Ctrl1 and Ctrl2 controllers.
DEMO
Javascript
.factory('Svc', function() {
var service = {
data: {}
};
// If you perform http requests or async procedures then set data.var1 here
service.data.var1 = true;
return service;
})
.controller('Ctrl1', function($scope, Svc) {
$scope.data = Svc.data;
})
.controller('Ctrl2', function($scope, Svc) {
$scope.data = Svc.data;
});
HTML
<div id="main">
<div ng-controller="Ctrl1">
<div ng-show="data.var1">Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
<hr>
<div ng-controller="Ctrl2">
<div ng-show="data.var1">More Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
</div>
So it seems I need to $watch the service for a change within the controller.
Original answer is here.
app.controller('Ctrl2', function($scope, Srvc) {
$scope.$watch(function () {
return Srvc.var1;
},
function(newVal, oldVal) {
$scope.var1 = newVal;
}, true);
});
I think setting Var1 to $rootScope instead of Srvc should work, just call $scope.$root.$digest() after updating var1.
and use ng-show=$root.Var1 in view.

Resources