It probably goes without saying that I'm quite new to angular as I'm trying to accomplish a relatively simple task, and I've come here for some help
I'm recreating our company's password vault using angular.
Here is what I am trying to accomplish.
The page loads with a list of accounts. Most the information is visible except for the password. I have a button that when clicked, hides the button, queries the database, logs who queried password, and displays the password to the user. The passwords are clear text because they aren't passwords for client accounts or anything sensitive, it exists for our employees to reference how/where to login to various websites we use for day to day business.
My HTML looks as follows:
<tr ng-repeat="account in resp.PasswordVaultAccounts">
<td>{{account.Name}}</td>
<td>{{account.Username}}</td>
<td><button ng-click="showPassword(account.AccountId);" class="btn btn-primary">View</button><span></span></td>
<td>{{account.Comments}}</td>
</tr>
My scope controller looks as follows
$scope.showPassword = function (accountId) {
passwordVaultData.getAccountPassword(accountId)
.$promise
.then(function (r) {
//success
}, function (r) {
//fail
});
}
My showPassword() method works and returns the correct password, but I can't figure out how to hide the button and display the password.
Using the ng-show and ng-hide directives against the password on the account object should suffice for modifying the UI
<tr ng-repeat="account in resp.PasswordVaultAccounts">
<td>{{account.Name}}</td>
<td>{{account.Username}}</td>
<td>
<button ng-hide="account.Password" ng-click="showPassword(account.AccountId);" class="btn btn-primary">View</button>
<span ng-show="account.Password">{{account.Password}}</span>
</td>
<td>{{account.Comments}}</td>
</tr>
As for the promise resolution, you want the getAccountPassword to return a promise, I will make an assumption about it's content below
function getAccountPassword(account) {
var deferred = $q.defer();
$http.get('api/vault/' + account.AccountId).then(function(r) {
deferred.resolve(r);
}, function(r) {
deferred.reject(r);
});
return deferred.promise;
}
$scope.showPassword = function (account) {
getAccountPassword(account.AccountId).then(function(password) {
account.Password = password;
}, function(password) {
account.Password = undefined; // some type of error handling here
});
}
Because the promise is executed in the context of an $http call, the digest cycle will run and the elements will be shown based on whether password is populated.
You can accomplish it by either ng-if or ng-show/hide:
Quick sample below:
<tr ng-repeat="account in resp.PasswordVaultAccounts">
<td>{{account.Name}}</td>
<td>{{account.Username}}</td>
<td>
<button ng-if="!account.password" ng-click="showPassword(account);" class="btn btn-primary">View</button><span></span></td>
<span ng-if="account.password">{{password}}</span>
<td>{{account.Comments}}</td>
</tr>
$scope.showPassword = function (account) {
account.password = passwordVaultData.getAccountPassword(account.AccountId)
.$promise
.then(function (r) {
//success
}, function (r) {
//fail
});
}
Please see demo below
var app = angular.module('app', []);
angular.module('app').
controller('firstCtrl', function($scope) {
$scope.resp = {
PasswordVaultAccounts: [{
AccountId: 1,
URL: "bbc.co.uk",
Username: "Jack",
Comments: "White"
}, {
AccountId: 2,
URL: "bbc.co.uk",
Username: "Mike",
Comments: "Green"
}, {
AccountId: 3,
URL: "bbc.co.uk",
Username: "Tim",
Comments: "Red"
}
]
}
$scope.showPassword = function(account) {
//call you backend and on sucess add that :
// passwordVaultData.getAccountPassword(account.accountId)
// .$promise
// .then(function (r) {
account.showpass = true;
account.pass = account.Username + " password is *****"
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="firstCtrl">
<table>
<tr ng-repeat="account in resp.PasswordVaultAccounts">
<td>{{account.Name}}
</td>
<td>{{account.Username}}</td>
<td>
<button ng-click="showPassword(account);" class="btn btn-primary" ng-hide="account.showpass">View</button>
<span ng-show="account.showpass">{{account.pass}}</span>
</td>
<td>{{account.Comments}}</td>
</tr>
</table>
</div>
</body>
Related
Hi I'm using angularJs in my client side. I have a view where a user can add and remove item like this:
app.controller('demoController', function($scope) {
// initial items
$scope.items = [
'item one',
'item two',
'item three'
];
// add an item
$scope.add = function() {
$scope.items.push($scope.input);
};
// remove an item
$scope.remove = function(index) {
$scope.items.splice(index, 1);
};`enter code here`
});
When the user finish, I want he clicks on a button. And after I will send all the items added and removed to a server to update database. I can't do this on each click because I need all the information to fill an email in my server part. I know how to remove and add item but I don't how to found removed items and add items and send them to the server. Please any one know how I can do this?
Thanks a lot.
You can do it with only using 1 array. You just have to create a new property and set it to true - if removed -, or false otherwise.
Then in your back-end you can get all the removed items accessing this property.
See the example below:
(function() {
'use strict';
angular
.module('app', [])
.controller('demoController', demoController);
demoController.$inject = ['$scope'];
function demoController($scope) {
// initial items
$scope.items = [
{
"name":"item one",
"removed":false
},
{
"name":"item two",
"removed":false
},
{
"name":"item three",
"removed":false
}
];
// add an item
$scope.add = function() {
$scope.items.push({
"name": $scope.input,
"removed": false
});
};
// remove an item
$scope.remove = function(index) {
$scope.items[index].removed = !$scope.items[index].removed;
};
}
})();
<!DOCTYPE HTML>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
</head>
<body ng-controller="demoController">
<table class="table table-hover">
<thead>
<tr>
<td>Name</td>
<td>Removed?</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items track by $index">
<td ng-bind="item.name"></td>
<td ng-bind="item.removed"></td>
<td>
<button type="button" class="btn btn-danger btn-sm" ng-click="remove($index)">Remove item</button>
</td>
</tr>
</tbody>
</table>
<hr>
<input type="text" class="form-control" ng-model="input" placeholder="Type to add">
<button type="button" class="form-control btn btn-primary btn-sm" ng-click="add()">Add item</button>
</body>
</html>
Note: If you don't want to show the removed items, you can simply check in your tr:
<tr ng-repeat="item in items track by $index" ng-if="!item.removed">
Now if you want to send both added and removed you have to actually store the removed ones somewhere either in the object itself with a flag like #developer033 suggested or either in an other object.
For me it is better to store all added and removed elements in one object. Now you do not need to click a button and send the change on every add or remove. When you are done with adding and removing you can just simply send the whole object with AJAX request to the server where you can do your logic:
function demoController($scope, $http, $q) {
$scope.submitItems = function(){
sendItems($scope.items).then(function () {
alert("Successfully deleted PT");
}, function (error) {
alert(error);
});
};
// ....
var sendItems = function (items) {
var request = $http({
url: _SERVER + 'edit/sendItems', // for example
method: 'POST',
data : items
params: {
}
});
return request.then(function (data) {
return $q.when(data);
}, function (error) {
return $q.reject(error);
});
}
// ....
}
It is a good practise to have a service from where you call the server and where this method sendItems should be. But we try to keep at as simple as possible.
Now in your rest controller in Spring you have to specify #RequestBody param:
#RequestMapping(value = "/sendItems", method = RequestMethod.POST)
public String editProductParameters(#RequestBody ArrayList<Item> items) {
//your logic goes here
return "Success"
}
Where the Item.class should consist the fields: String name and boolean remove also should have a deffault constructor(deffault constructur is specified if there are none implementations of constructurs in the class or if there is a constructor with no arguments) also create getters and setter about the two fields. Thouse are the requirements that are needed to pass the whole array of objects($scope.items) from the client to the server with default mapping.
Good luck
I want to disable button Assign when it clicked, bacause it should assign only once so i can achieve this, I have done the following code in HTML:
<table class="table details">
<thead>
<tr>
<th sort-by="firstName">User Name</th>
<th sort-by="lastName">Description</th>
<th sort-by="Budget" sort-init="desc">Bid Amount</th>
<th sort-by="lastName">Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="issue in issues | filter:filter">
<td><strong><a href="/ViewBid/Index?{{ issue.User_ID }}" />{{ issue.UserName }} </strong></td>
<td><a href="/ViewBid/Index?{{ issue.User_ID }}" />{{ issue.Description }}</td>
<td><a href="/ViewBid/Index?{{ issue.User_ID }}" />{{issue.Bid_amt}}</td>
<td>
<div ng-controller="ExampleCtrl_Assign">
<div ng-show="AsgHide">
<button type="button" ng-click="AssignRecord(issue.ID,issue.Description,issue.Bid_amt)">Assign</button>
</div>
</div>
<div ng-controller="ExampleCtrl_Delete">
<div ng-show="AsgHide" >
<button type="button" ng-click="DeleteRecord(issue.ID)">Delete</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
And JavaScript Code is as following:
var app = angular.module('siTableExampleApp_Assign', []);
app.controller('ExampleCtrl_Assign', ['$scope','$http', function ($scope, $http) {
var user2 = window.localStorage.getItem('UserId');
var Basic = window.localStorage.getItem('Basic');
var Token = window.localStorage.getItem('Token');
$scope.FunctionDisable = function (i) {
$("#rbutton'+i+'").attr("disabled", "disabled");
}
$scope.AssignRecord = function (ID, Description, Bid_amt) {
var BidID = ID;
var date = new Date();
encodedString = {
"ID": 1,
"Travel_Info_ID": travel_info_id,
"Bid_ID": parseInt(BidID),
"Description": Description,
"Bid_amt": Bid_amt,
"Status": "InProcess",
"User_ID": user2,
"Entry_Date": date,
"Update_Date": date
}
$http({
method: 'POST',
url: 'http://saisoftwaresolutions.com/v1/Assigned_Bids/Assigned_Bid/Create',
data: encodedString,
headers: {
'Authorization': 'Basic ' + Basic,
'Token': Token
}
})
.success(function (data, status, headers, config) {
console.log(headers());
console.log(data);
if (status === 200) {
//window.location.href = 'http://localhost:22135/BDetail/Index';
} else {
$scope.errorMsg = "Login not correct";
}
})
.error(function (data, status, headers, config) {
$scope.errorMsg = 'Unable to submit form';
})
Use can always use ng-disabled directive provided by Angular to disabled html elements.
I have made one example based on your requirements and help it will solve your issue:
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in items">{{item.User_ID}}: {{item.User_Name}}
<button ng-click="handleClick($index)" ng-disabled="item.disabled">
{{item.User_Name}}
</button>
</li>
</ul>
</div>
function MyCtrl($scope) {
$scope.items = [
{
User_ID: '10',
disaled: false,
User_Name: 'ABC'
}, {
User_ID: '11',
disaled: false,
User_Name: 'XYZ'
}
];;
$scope.handleClick = function(index){
$scope.items[index].disabled = true;
}
}
Angular has a directive just for this: ng-disabled.
From their official documentation:
This directive sets the disabled attribute on the element if the
expression inside ngDisabled evaluates to truthy.
So you can set a boolean value in your code-behind to true and have that evaluate inside your button. For example:
<button type="button" ng-disabled="issue.IsDisabled" ng-click="AssignRecord(issue.ID,issue.Description,issue.Bid_amt)">Assign</button>
Also, check out the example in their documentation and this jsfiddle: https://jsfiddle.net/simpulton/q8r4e/.
I am using MEAN JS, i am trying to edit the list items on the list page, but it shows the error as below. i have initiated the data using ng-init="find()" for the list and ng-init="findOne()" for individual data.
Error: [$resource:badcfg] Error in resource configuration for action `get`. Expected response to contain an object but got an array
HTML
Below i the form inside the controller where it initiates the find() and findOne().
<div ng-controller="OrdersController" ng-init="find()">
<div>
<div class="order-filter">
<div ng-repeat="order in orders">
<form ng-init="findOne()" name="orderForm" class="form-horizontal" ng-submit="update(orderForm.$valid)" novalidate>
<input type="text" class="" ng-model="order.title">
<input type="text" class="" ng-model="order.content">
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
</form>
</div>
</div>
</div>
</div>
Controller
$scope.update = function (isValid) {
$scope.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'orderForm');
return false;
}
var order = $scope.order;
order.$update(function () {
$location.path('orders/' + order._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.find = function () {
Orders.query(function loadedOrders(orders) {
orders.forEach(appendFood);
$scope.orders = orders;
});
};
$scope.findOne = function () {
$scope.order = Orders.get({
orderId: $stateParams.orderId
});
};
You need to check your Orders Service which probably is using $resource to provide your API requests (Orders.query)
It should look something like this:
function OrdersService($resource) {
return $resource('api/orders/:orderId', {
orderId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
The style may be different depending on which version of mean you're using. By default, the $resource query will expect an array of results, but if for some reason you've set "isArray" to false then it will expect an object.
https://docs.angularjs.org/api/ngResource/service/$resource
My code is like this
<body ng-app="myApp" ng-controller="MainCtrl">
<div>Name only
<input ng-model="search.name" />
<br />
<table id="searchObjResults">
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
<tr ng-repeat="friendObj in friends | filter:search:strict | limitTo:1">
<td>{{friendObj.name}}</td>
<td>{{friendObj.phone}}</td>
</tr>
</table>
</div>
<div>
<button type="button" id="btn_submit" ng-click="submitForm()">Get rates</button>
</div>
angular.module('myApp', []).controller('MainCtrl', ['$http', '$scope', function ($http, $scope) {
$scope.friends = [{
name: 'John',
phone: '555-1276'
}, {
name: 'Mary',
phone: '800-BIG-MARY'
}, {
name: 'Mike',
phone: '555-4321'
}, {
name: 'Adam',
phone: '555-5678'
}, {
name: 'Julie',
phone: '555-8765'
}, {
name: 'Juliette',
phone: '555-5678'
}];
$scope.submitForm = function () {
// i want to get the data here
};
}]);
As you can see at a time only one friend will be active on my screen. when I press my submit button, I want that data (filtered single row) to be the only value on my current $scope.friends so that I can send it to an external service as the selected data. Can any one point out what i need to do here
Fiddle
Note: I can't change the position of this button.
Why not make your button part of the table row, since there will only ever be one? Here is a JSFiddle showing it working in that fashion.
The ng-click function handler for the button can then simply take a parameter that is the actual friendObj you are interested in:
<button type="button" ng-click="submitForm( friendObj )">Get rates</button>
EDIT: There is actually a way to do this if you can't move the button; make the ng-repeat operate over a NEW array, which will be accessible outside of the ng-repeat. So your ng-repeat statement becomes:
<tr ng-repeat="friendObj in newArray = (friends | filter:search:strict | limitTo:1)">
And then your button can simply reference the one-element array:
<button type="button" ng-click="submitForm( newArray )">Get rates</button>
Updated Fiddle here :-)
Try this:
$scope.submitForm = function () {
var data = $filter('filter')($scope.friends, $scope.search.name);
};
Fiddle here.
If you put the filter in the controller instead of the view, you could set a variable like $scope.result that the submitForm function could use. For example, in your HTML, you could add an ng-change directive to your search field like so:
<input ng-model="search.name" ng-change="updateResult()" />
Then, instead of using ng-repeat, you'd use ng-show to show the one result, or hide the row if there is no result:
<tr ng-show="result">
<td>{{result.name}}</td>
<td>{{result.phone}}</td>
</tr>
Then in your controller:
$scope.search = {name: ''};
$scope.updateResult = function() {
$scope.result = $filter('filter')($scope.friends, $scope.search.name)[0];
}
$scope.updateResult();
// ...
$scope.submitForm = function() {
// $scope.result can be used here
}
EDIT: The advantage of this approach is it's a bit DRYer because you don't re-filter inside submitForm. MarcoS's approach has the advantage of being a lot shorter!
I have a User object in Angular controller. I also have an array of Account objects with respective ID for each.
In User I have a field "default_account" where I want to put ID of a default account. So, user can have a lot of accounts but only one of them can be default. When I go to Account options, I have a checkbox there which is responsible for setting/unsetting the account as default.
Now I want to set checkbox on/off depending on its being default for the user. And I also need to respectively change default_account field inside User object on checkbox change. It puzzles me quite much how I can do it.
Any advice is appreciated!
Very approximate (didn't text that):
html:
<div ng-repeat="account in accounts">
<input type="checkbox" ng-checked="account == user.default_acount"
ng-click="SelectAssDefault(account )" />
</div>
js:
function MyCtrl($scope) {
$scope.user = { name: 'user', default_acount: null};
$scope.accounts = [{ }, { }, ...];
$scope.SelectAssDefault = function (account) {
$scope.user.default_acount = account;
};
}
EDIT: a working example: http://jsfiddle.net/ev62U/120/
If you want to set a checkbox to true based on a variable, you can set ng-checked="variable" within the input tag.
If the variable is true the box will be checked. If it's false it won't. Alternatively, an expression will also work e.g. ng-checked="1===1" will evaluate to true.
If you want to alter something else based on user clicking on the checkbox, set ng-click="someCtrlFunction()" within the input tag. This will call a function in your controller. You can look up the value of the checkbox from your controller if you've bound to it.
Here's a fiddle: http://jsfiddle.net/E8LBV/10/ and here's the code:
HTML
<div ng-app="App">
<div ng-controller="AppCtrl">
<ul>
<li ng-repeat="user in users">{{user.name}}
<ul>
<li ng-repeat="account in user.accounts">
<input type="checkbox" ng-model="checked" ng-checked="account == user.default" ng-click="changeDefault(user.id,account,checked)">{{account}}</input>
</li>
<ul/>
</li>
</ul>
</div>
</div>
JS
var app = angular.module('App', []);
app.service('Users', function () {
var Users = {};
Users.data = [{
'id': 1,
'name': 'jon',
'default': null
}, {
'id': 2,
'name': 'pete',
'default': null
}];
return Users;
});
app.service('Accounts', function () {
var Accounts = {};
Accounts.data = [{
'user': 1,
'ac': 123456
}, {
'user': 2,
'ac': 456832
}, {
'user': 2,
'ac': 345632
}, {
'user': 1,
'ac': 677456
}];
return Accounts;
});
app.controller('AppCtrl', function ($scope, Users, Accounts) {
$scope.users = Users.data;
//attach accounts to user
for (i = 0; i < $scope.users.length; i++) {
$scope.users[i].accounts = [];
for (ii = 0; ii < Accounts.data.length; ii++) {
if (Accounts.data[ii].user == $scope.users[i].id) {
$scope.users[i].accounts.push(Accounts.data[ii].ac);
}
}
}
//function to change the default account for the user
$scope.changeDefault = function (id, account, checked) {
if (!checked) {
return;
}
for (i = 0; i < $scope.users.length; i++) {
if ($scope.users[i].id == id) {
$scope.users[i].
default = account;
}
}
}
});
Here is my solution that perfectly worked for me!
<tbody ng-repeat="account in accounts">
<tr>
<td ><a ng-click="getloandetails(account.idAccount)">{{account.accountName}}</a></td>
<td>$ {{account.currentBalance}}</td>
</tr>
</tbody>
and in Angular side just do this:
$scope.getloandetails = function(accountId) {
alert('Gettring details for the accountId: ' + accountId);
};