Targeting $index from ng-repeat - angularjs

How would I go about targeting this model in the controller?
formData[$index].ID
This is not working -
$scope.getJob = function() {
Employee.get({id: "" + $scope.formData[$index].ID}, function (data) {
console.log(data);
})
}

You would actually inject the object or index from your template. Something like this:
<div ng-repeat="o in formData">
<button ng-click="getJob($index)">Click me!</button>
</div>
and then in your code:
$scope.getJob = function(idx) {
Employee.get({id: "" + $scope.formData[idx].ID}, function (data) {
console.log(data);
})
}
Alternatively, instead of injecting the index, you could inject the entire object:
<div ng-repeat="o in formData">
<button ng-click="getJob(o)">Click me!</button>
</div>
and then in your code:
$scope.getJob = function(o) {
Employee.get({id: o.ID}, function (data) {
console.log(data);
})
}

Related

How do I get ng-init to work with mutiple functions in a controller?

My html:
<div ng-app="APSApp" class="container">
<br />
<br />
<input type="text" placeholder="Search Terms" />
<br />
<div ng-controller="APSCtl" >
<table class="table">
<tr ng-repeat="r in searchTerms" ng-init="searchTerms=getSearchTerms()" >
<td>{{r.DisplayText}} <input type="text" ng-model="r.SearchInput"></td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
const moduleId = '#Dnn.ModuleContext.ModuleId';
const tabId = '#Dnn.ModuleContext.TabId';
</script>
<script src="/DesktopModules/RazorCart/Core/Content/Scripts/angular.min.js"></script>
<script src="/DesktopModules/MVC/AdvancedProductSearchMVC/Scripts/AdvancedProductSearch.js"></script>
My angular setup:
var aps = angular.module("APSApp", []);
aps.config(function($httpProvider) {
$httpProvider.defaults.transformRequest = function(data) {
return data !== undefined ? $.param(data) : null;
};
});
aps.factory('SearchTerms',
function($http) {
return {
getSearchTerms: function(onSuccess, onFailure) {
const rvtoken = $("input[name='__RequestVerificationToken']").val();
$http({
method: "post",
url: "/DesktopModules/MVC/AdvancedProductSearchMVC/AdvancedProductSearch/GetAPS",
headers: {
"ModuleId": moduleId,
"TabId": tabId,
"RequestVerificationToken": rvtoken
}
}).success(onSuccess).error(onFailure);
}
};
});
aps.controller('APSCtl',
function(SearchTerms, $scope) {
function getSearchTerms() {
$scope.searchTerms = [];
successFunction = function(data) {
$scope.searchTerms = data;
console.log($scope.searchTerms);
};
failureFunction = function(data) {
console.log('Error' + data);
};
SearchTerms.getSearchTerms(successFunction, failureFunction);
}
function doSomethingElse($scope) {}
});
I'm trying to create a single controller with multiple functions. This works if my angular controller looks like this (and I don't use ng-init):
aps.controller('APSCtl',
function(SearchTerms, $scope) {
$scope.searchTerms = [];
successFunction = function(data) {
$scope.searchTerms = data;
console.log($scope.searchTerms);
};
failureFunction = function(data) {
console.log('Error' + data);
};
SearchTerms.getSearchTerms(successFunction, failureFunction);
});
I was just trying to keep related functions in a single controller. What am I doing wrong? Do I actually have to set up a different controller for each function?
You do not have to assign the value in the template, you can just call the function,
<table class="table" ng-init="getSearchTerms()>
<tr ng-repeat="r in searchTerms" >
<td>{{r.DisplayText}} <input type="text" ng-model="r.SearchInput"></td>
</tr>
</table>
you should have a function named getSearchTerms() in your controller to get it called,
aps.controller('APSCtl',
function(SearchTerms, $scope) {
$scope.getSearchTerms() {
$scope.searchTerms = [];
successFunction = function(data) {
$scope.searchTerms = data;
console.log($scope.searchTerms);
};
failureFunction = function(data) {
console.log('Error' + data);
};
SearchTerms.getSearchTerms(successFunction, failureFunction);
}
function doSomethingElse($scope) {}
});

Get ng-model in ng-repeat in ng-repeat with Protractor

How can I get the ng-model in ng-repeat in ng-repeat with protractor ?
<div ng-repeat="field in master.linker | orderBy:'country.name'">
<div>
<p> {{ field.country_name }} </p>
<label ng-repeat="user in user_list">
<input type="checkbox" ng-model="selected_user">
<span ng-bind="user.name"></span>
</label>
</div>
</div>
I use filter() to check my ng-repeat :
var fields = element.all(by.repeater('field in master.linker'));
fields.filter(function (field) {
return field.element(by.binding("field.country_name")).getText().then(function (country) {
return country === "en";
});
}).then(function (filteredFields) {
var fields2 = filteredFields[0].element.all(by.repeater('user in user_list'));
return fields2.filter(function (field2) {
return field2.element(by.binding('user.name')).getText().then(function (value) {
return value === user;
});
}).then(function (filteredFields) {
var myuser = filteredFields[0].element(by.model('user_name'));
self.current_step.expect(input.getAttribute('value')).to.eventually.equal('');
});
});;
I have this error in my console :
TypeError: filteredFields[0].element.all is not a function
Use .all() instead of .element.all():
filteredFields[0].all(by.repeater('user in user_list'));
You can also simplify things using first():
var fields = element.all(by.repeater('field in master.linker'));
var filteredUser = fields.filter(function (field) {
return field.element(by.binding("field.country_name")).getText().then(function (country) {
return country === "en";
});
}).first().all(by.repeater('user in user_list')).filter(function (userField) {
return userField.element(by.binding('user.name')).getText().then(function (value) {
return value === user;
});
}).first();
var myuser = filteredUser.element(by.model('user_name'));
self.current_step.expect(myuser.getAttribute('value')).to.eventually.equal('');
You may also look into the column() and row() repeater API.

Refresh $scope variables from a service

What is the proper method of refreshing data that is retrieved from a service? I am retrieving a test array from my dataService that I'd like to be automatically updated in my view when my save() method is called. I have commented the line that is supposed to update my $scope variable but yet nothing changes. Should I be wrapping it in $apply()?
The data that is placed into the array that dataService.getActivities() returns is from a cookie (which may or not be relevant).
app.controller("activityCtrl", ["$scope", "dataService", function ($scope, dataService) {
$scope.newActivity = "";
$scope.activities = dataService.getActivities();
$scope.save = function (activity) {
try{
if (activity != "") {
dataService.saveActivity(activity);
$scope.newActivity = "";
$scope.activities = dataService.getActivities(); //HERE
}
} catch (e) {
alert(e);
}
}
}
Here is my view, the array lives in a ng-repeat
<div class="col-xs-12" ng-controller="activityCtrl">
<div class="row text-center">
<form novalidate>
<input type="text" placeholder="Activity name" ng-model="newActivity" />
<input type="submit" value="Add activity" ng-click="save(newActivity)" />
</form>
</div>
<div class="row" ng-controller="activityCtrl">
<div class="col-xs-2"> </div>
<div class="col-xs-6 text-left">
<div class="row" ng-repeat="activity in activities">
<div class="btn btn-default" ng-class="{ active : activity.active }" ng-click="activate(activity)">{{ activity.name }}</div>
</div>
</div>
<div class="col-xs-4 text-left">
sdfas
</div>
</div>
</div>
dataService code:
app.service("dataService", function () {
this.getActivities = function () {
if (docCookies.hasItem("activities")) {
var activities = JSON.parse(docCookies.getItem("activities"));
if (activities.constructor != Array) {
activities = [activities];
}
activities.sort(
function (a, b) {
if (a.name > b.name) { return 1; }
if (b.name < a.name) { return -1; }
return 0;
});
return activities;
}
return [];
}
this.saveActivity = function (activity) {
if (!docCookies.hasItem("activities")) {
docCookies.setItem("activities", [JSON.stringify({ "name": activity, "active": true })], Infinity);
} else {
var activities = this.getActivities();
for (var i = 0; i < activities.length; i++) {
if (activities[i].name == activity) {
throw "Activity already exists";
}
}
activities.push({ "name": activity, "active": false });
docCookies.setItem("activities", JSON.stringify(activities), Infinity);
}
};
});
Zac, your answer should work for you. As another option, I like to broadcast an event whenever my service is updated. In the last line of your saveActivity() function in your service, try broadcasting an event on the rootScope. Inject the $rootScope into your service. Add the following to your save method:
$rootScope.$broadcast('activitiesUpdated');
Then in your controller, inject the $rootScope and add an event handler:
$rootScope.$on('activitiesUpdated', function(event, args){
//Update $scope variable here
});
The answer was to look at the cookie value with a call to $watch instead of the method that returns an object. Added this in my activityCtrl
$scope.$watch(function () {
return docCookies.getItem("activities");
}, function (oldVal, newVal) {
$scope.activities = dataService.getActivities();
});

AngularFire $remove item from Array using a variable in Firebase reference does not work

I've been struggling with the following problem:
I'm trying to delete a 'Post' item from a Firebase Array with the $remove AngularFire method which I have implemented in a Angular Service (Factory). This Post is a child of 'Event', so in order to delete it I have to pass this Service a argument with the relevant Event of which I want to delete the post.
This is my controller:
app.controller('EventSignupController', function ($scope, $routeParams, EventService, AuthService) {
// Load the selected event with firebase through the eventservice
$scope.selectedEvent = EventService.events.get($routeParams.eventId);
// get user settings
$scope.user = AuthService.user;
$scope.signedIn = AuthService.signedIn;
// Message functionality
$scope.posts = EventService.posts.all($scope.selectedEvent.$id);
$scope.post = {
message: ''
};
$scope.addPost = function (){
$scope.post.creator = $scope.user.profile.username;
$scope.post.creatorUID = $scope.user.uid;
EventService.posts.createPost($scope.selectedEvent.$id, $scope.post);
};
$scope.deletePost = function(post){
EventService.posts.deletePost($scope.selectedEvent.$id, post);
// workaround for eventService bug:
// $scope.posts.$remove(post);
};
});
And this is my Service (Factory):
app.factory('EventService', function ($firebase, FIREBASE_URL) {
var ref = new Firebase(FIREBASE_URL);
var events = $firebase(ref.child('events')).$asArray();
var EventService = {
events: {
all: events,
create: function (event) {
return events.$add(event);
},
get: function (eventId) {
return $firebase(ref.child('events').child(eventId)).$asObject();
},
delete: function (event) {
return events.$remove(event);
}
},
posts: {
all: function(eventId){
var posts = $firebase(ref.child('events').child(eventId).child('posts')).$asArray();
return posts;
},
createPost: function (eventId, post) {
// this does work
var posts = $firebase(ref.child('events').child(eventId).child('posts')).$asArray();
return posts.$add(post);
},
deletePost: function (eventId, post) {
// this does not work
var posts = $firebase(ref.child('events').child(eventId).child('posts')).$asArray();
return posts.$remove(post);
}
}
};
return EventService;
});
When I try to delete the link tag just freezes and no error logging appears in the console. While if I call $remove on my $scope.posts directly in my controller it magically works.. Furthermore my Post is not removed from my Firebase DB.
Another weird thing is that 'CreatePost' works perfectly fine using the same construction.
My view:
<div class="col-xs-8 col-xs-offset-2 well">
<form ng-submit="addPost()" ng-show="signedIn()">
<input type="text" ng-model="post.message" />
<button type="submit" class="btn btn-primary btn-sm">Add Post</button>
</form>
<br>
<div class="post row" ng-repeat="post in posts">
<div>
<div class="info">
{{ post.message }}
</div>
<div>
<span>submitted by {{ post.creator }}</span>
delete
</div>
<br>
</div>
</div>
</div>
P.s. I'm not too sure that my 'Service' is implemented in the best possible way.. I couldn't find another solution for doing multiple firebase calls
var posts = $firebase(ref.child('events').child(eventId).child('posts')).$asArray();
within the Post part of my EventService, because it depends on eventId in each CRUD operation. Any ideas would be very welcome :)
The easiest way for me was to use this:
var ref= new Firebase('https://Yourapp.firebaseio.com/YourObjectName');
ref.child(postId).remove(function(error){
if (error) {
console.log("Error:", error);
} else {
console.log("Removed successfully!");
}
});
The only way I'm able to remove the item is using a loop on the array we get from firebase.
var ref= new Firebase('https://Yourapp.firebaseio.com/YourObjectName');
var arr_ref=$firebaseArray(ref);
for(var i=0;i<arr_ref.length;i++){
if(key==arr_ref[i].$id){
console.log(arr_ref[i]);
arr_ref.$remove(i);
}
}

How can I use the exact same array from one service in two controllers?

I have this code:
controller:
function deleteRootCategory(){
$scope.rootCategories[0] = '';
}
function getCategories(){
categoryService.getCategories().then(function(data){
$scope.rootCategories = data[0];
$scope.subCategories = data[1];
$scope.titles = data[2];
});
}
getCategories();
service:
var getCategories = function(){
var deferred = $q.defer();
$http({
method:"GET",
url:"wikiArticles/categories"
}).then(function(result){
deferred.resolve(result);
});
}
return deferred.promise;
}
html:
<div ng-controller="controller">
<div ng-repeat="root in rootCategories"> {{root}} </div>
<div ng-repeat="sub in subCategories"> {{sub}} </div>
<div ng-repeat="title in titles">{{title}}</div>
</div>
html2:
<div ng-controller="controller">
<div ng-include src="html"></div>
<button ng-click="deleteRootCategory()">Del</button>
</div>
When I click the deleteRootCategory-button the array $scope.rootCategories is updated, but the view won't ever change.
What am I missing?
Thanks
You will probably want to have a broadcast event set up when the value is changed in the service. Something like this.
.service("Data", function($http, $rootScope) {
var this_ = this,
data;
$http.get('wikiArticles/categories', function(response) {
this_.set(response.data);
}
this.get = function() {
return data;
}
this.set = function(data_) {
data = data_;
$rootScope.$broadcast('event:data-change');
}
});
Have both controllers waiting for the event, and using the set to make any changes to the array.
$rootScope.$on('event:data-change', function() {
$scope.data = Data.get();
}
$scope.update = function(d) {
Data.set(d);
}

Resources