I am using Angular 1.0.8 along with Restangular for this. Since I am just starting out in js framework in general, a newbie-friendly explanation would be greatly appreciated.
I have a very simple HTML <section> like this (ng-app has been defined in body):
<section class="comment-list block scrollable wrapper" style="height:350px" ng-controller="MessageStreamController">
<div> {{ message.message }} </div>
<div class="input-group">
<input type="text" class="form-control" ng-change="change()" ng-model="message.message" placeholder="Input your comment here">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="clicked()">POST</button>
</span>
</div>
</section>
with the following <script>
var JApp = angular.module('JApp', ['restangular']);
JApp.controller('MessageStreamController', function($scope, Restangular) {
var service = Restangular.all('message-stream');
$scope.clicked = function() {
$scope.message = service.one('index', 1).get();
}
})
In the backend /message-stream/index/1 it simply returns
return json_encode(array(
'message' => 'Hey there James',
'user' => 'Terry'
));
This results in the <div> {{ message.message }} </div> and input gets rendered with 'Hey there James'. All good so far.
But then I can't edit the input box afterwards.
Some questions pointed out that this happens when you don't use ng-repeat, but then again I am expecting one JSON object from the backend.
Any pointer here to help?
UPDATE:
Changed from Restangular to $resource fixes my problem. Though would love to know why this is happening. Answer from people who has experience with Restangular will be appreciated.
Restangular returns a promise from all queries which can not be edited.
Instead you should assign the actual result to your scope as per the answer to this question - Angular.JS: why can't the inputs be edited?
Related
Long story short, I have this div inside my app.component.html:
<div class="col-lg-6 search-div">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
Which shows:
And I would like for it to show available values according to a function I have in the my app.component.ts:
public getUsers() {
return this.restService.getUsers().subscribe(
jsonElements => {
var users = jsonElements;
},
error => this.errorMessage = <any>error);
}
I can even pre-store the result:
users = this.getUsers();
But then how would I filter by users?
Is there an easy way to accomplish this ?
There is already an HTML solution for what you want, the 'datalist' tag does what you want. The only problem with it is that it does not have great browser support. You can read more at https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist.
So you would use it like
<input list="users"/></label>
<datalist>
<option *ngFor='let user of users' value="user">
</datalist>
You're looking for an autocomplete.
You can find an example here with a plunker but others are available as well.
I'm building a dynamically generated form from a database using ng-repeat in Node.js and Angular. All of the text boxes are replicating the text entered on any one of the text boxes. So, if I type "xyz" in one text box, all of them have "xyz". But, if I submit the results, it only updates that one form reference.
This is the HTML:
<div class="container">
<div class="todo-form">
<form class="form-inline" ng-repeat="todo in todoData">
<li>
<h4>Country Code: {{ todo.country_code }} <input id="{{ todo.country_code }}" type="text" class="form-control input-sm" placeholder="{{ todo.country_name }}" ng-model="formData.text">
<button type="submit" class="btn btn-default" ng-click="updateTodo(todo.country_code)">Update</button></h4><br>
</li>
</form>
</div>
This is the JS it refers to:
angular.module('editTodo', [])
.controller('editController', ($scope, $http) => {
$scope.formData = {};
$scope.todoData = {};
// Get Org Details
$http.get('ref_country_code_get')
.success((data) => {
$scope.todoData = data;
console.log(data);
})
.error((error) => {
console.log('Error: ' + error);
});
Clearly, I need to disable this. I've tried to add a name= or ID={{ todo.country_code }} into the form to make it unique, but that doesn't work. Why are the all acting like they are the same text box? I'm new to Node.js and very rusty with my HTML, but I can't find any reference to this phenomena. Maybe it is too basic that nobody makes this mistake? %)
Andy F solved the issue. Simply replace the ng-model="formdata.txt" to ng-model="todo.txt". Now, none of the text boxes replicate what is typed in any other text box.
hope you guys are kicking and jumping. Thanks for your usual understanding.
Frameworks: AngularJS, NodeJS
I am designing a login page. But the data to be compared with is an array of items in testData.html. I want to call the data on the login.html and compare it with user's input.
The login form works properly but the data is not read. I tried compiling the dataobject.html file separately, and it did not run.
I do not want to store this data in a .json file.
Later I will learn how to use the MongoDB to read data and compare
Please check the codes below.
[LOGIN.HTML]
<div ng-app="myApp" ng-controller="loginCtrls" style="height:auto;">
<form name="lForm">
<div class="container">
<label><b>Username</b></label>
<input class="w3-round" type="text" name="username" placeholder="Username" ng-model="username" required>
<div align="right" style="width:550px;">
<span style="color:red" ng-show="lForm.username.$dirty && lForm.username.$invalid">
<span ng-show = "lForm.username.$error.required">Username is required.</span>
</span>
</div>
<label><b>Password</b></label>
<input class="w3-round" type="password" name="password" ng-model="password" placeholder="Password" required>
<div align="right" style="width:550px;">
<span style="color:red" ng-show="lForm.password.$dirty && lForm.password.$invalid">
<span ng-show = "lForm.password.$error.required">Password is required.</span>
</span>
</div>
<div align="center">
<button class="w3-btn w3-teal w3-round" style="height:45px; width:100%; font-size:16px;" ng-disabled = "lForm.username.$dirty && lForm.username.$invalid || lForm.password.$dirty && lForm.password.$invalid" ng-click="chkData()">Click to Login</button>
</div>
<input type="checkbox" checked="checked"> Remember me
</div>
<div class="container" style="background-color:#f1f1f1; margin-top:0;">
<span>Forgot password?</span>
</div>
</form>
<h4>{{result}} login attempt</h4>
</div>
<script src="js/loginCtrl.js"></script>
[LOGINCTRL.JS]
// JavaScript Document
var app = angular.module('myApp', []);
app.controller('loginCtrls', function($scope, $http) {
//get the file from the dataobject.html file
$http.get("dataobject.html").then(function (response) {
//parse the array object to $scope.users
$scope.users = response.data.records;
});
//this function checks the user's input and
//compares it with the any match in object array
//the object array data has been passed into $scope.users
$scope.chkData = function(){
$scope.users = $scope.data.records;
angular.forEach($scope.users, function(value, key){
if(angular.equals(value.Username, $scope.username) && (value.Password, $scope.password)){
$scope.result = "Successful ";//msg to be displayed
}else {
$scope.result = "Unsuccessful ";//msg to be displayed
}
});
}
});
[DATA OBJECT.HTML]
<script src = "js/angular.min.js" type="text/javascript"></script>
<div ng-app="myApp" ng-controller="mdata">
</div>
<script>
var app = angular.module('myApp', []);
app.controller('mdata', function($scope) {
$scope.data =
{ "records":[ {"Username":"Alfreds","Password":"alfred","Session ID":"1"}, {"Username":"Ana","Password":"ana","Session ID":"2"}, {"Username":"Moreno","Password":"moreno","Session ID":"3"}] };
});
});
</script>
I would recommend to do it using a service. Angular services are singletons. So, from one controller, you put the data in a service, switch pages, get the data from the service.
NOTE: if user refreshes the page, the data in the service will be lost, as services (or angular for that matter) does not persist state.
ofc, everyone will have their own solution. I see you are a beginner, so the answer is meant to help you get a grasp of angular.
You can store your data either on the $rootScope or by creating localStorage Services and u can access data anywhere in application but the best practices are creating some localStorage services.
Is there a way to access $route from the html side of AngularJS?
I'd really like to do something like this in HTML and eliminate yet another $scope function. (yes, i know its not really something that works):
<button ng-disabled="!route.current.scope.currentform.$valid">
I am working on a large angular application that is somewhat 'down the road' in the development cycle. At this time we have decided to implement form validation (don't ask why it wasn't 1 or 2 on the list).
I am currently using two buttons in the footer "previous" and "next", both which need to ng-disabled set to !$scope.formname.$valid. This needs to work across multiple controllers / pages, since the buttons are in my footer on index.html.
The code i'm using right now looks like this:
// Want to eliminate this isFormValid() method
$scope.isFormValid = function() {
if ($route.current) {
if ($route.current.scope) {
return !$route.current.scope.currentform.$valid;
}
}
};
$scope.prevPage = function() {
if (angular.isFunction($route.current.scope.PrevAction)) {
// do stuff particular to the current controller
$route.current.scope.PrevAction()
}
};
$scope.nextPage = function() {
if (angular.isFunction($route.current.scope.NextAction)) {
// do stuff particular to the current controller
$route.current.scope.NextAction()
}
};
and the corresponding button code is as follows:
<div class="footer">
<button id="main-prev-button" type="button" class="btn btn-primary previous" ng-click="prevPage($event)" ng-disabled="isFormValid()">Previous</button>
<button id="main-next-button" type="button" class="btn btn-primary next" ng-click="nextPage($event)" ng-disabled="isFormValid()">Next</button>
</div>
Each page code looks something like this
<ng-form id="currentform" name="currentform">
<label>Full Name</label>
<input type="text" class="form-control" ng-model="nl.firstName" id="firstName" placeholder="First Name" name="firstName" ng-minlength="5" ng-maxlength="20" ng-required="true">
<pre>currentform.firstName.$error = {{ currentform.firstName.$error | json }}</pre>
<ng-messages for="currentform.firstName.$error">
<ng-message when="required">You did not enter a field</ng-message>
<ng-message when="minlength">Your field is too short</ng-message>
<ng-message when="maxlength">Your field is too long</ng-message>
</ng-messages>
</ng-form>
Add the $route to the root scope $rootScope and then access it in your html/view using the $rootScope.$route.
E.g:
angular.module('myApp').run(['$rootScope', '$route',
function ($rootScope, $route) {
$rootScope.$route = $route;
}]);
There is an object that contains a list of error messages: error code + error text. There is an array of error messages (array of error codes) I would like to display on the page (in some places) without any additional validation.
I've tried to do that here in jsFiddle with AngularJS, but seems like I could be on the wrong way of how to do it better as I'm new to AngularJS. That's why I'm asking SO community to think and to help, if that's look an interesting problem.
Here is a code below or check from jsFiddle.
Beside angular.js, angular-messages.js was added as well:
HTML:
<h3>So what I need here is actually to display errors that are returned by my custom showErrorsWeWant service. The array of errors can be different. No additional validation is needed. As result, I'm not sure if to stick with ng-message(s) or ng-if(s) (so both ng-message and ng-if are used in this example)</h3>
<h4>
As result, once the page is loaded, only 'You did not enter your name' and "'text for error04'" should be displyaed, based on
return ['error01', 'error04'];
</h4>
<h5>For three errors in returned array - then 3 respective errors displayed for these two inputs.
The very <u>IMPORTANT</u> thing: I don't know how to stick so each error know its place - is it for first input or for the second one. Still thinking how to make it done. Probably the additional property should be assigned in the json object.</h5>
<form name="myForm">
<label>Name:</label>
<input type="text" name="myName" ng-model="name" ng-minlength="5" ng-maxlength="5" required placeholder="type here" />
<div ng-messages="myForm.myName.$error" style="color:red; padding-left: 60px;">
<div ng-message="required">{{ errors['error01'] }}</div>
<div ng-message="minlength">{{ errors['error02'] }}</div>
<div ng-message="maxlength">{{ errors['error03'] }}</div>
</div>
</form>
<div id="statusBlock">
<label>City:</label>
<input type="text" placeholder="and type here">
<div style="color:red; padding-left: 60px;">
<div ng-if="errorsArr[1]=='error04'">{{ errors['error04'] }}</div>
<div ng-if="1<3">{{ errors['error05'] }}</div>
<div ng-message="maxlength">{{ errors['error06'] }}</div>
</div>
</div>
</div>
</body>
JS code:
var myApp = angular.module('myApp', ['ngMessages']);
myApp.controller('myController', ['$scope', 'showErrorsWeWant', function ($scope, showErrorsWeWant){
$scope.name = "";
$scope.errors= {
error01: 'You did not enter your name',
error02: 'Your name is less than 5 symbols',
error03: 'Yr name is 6+ symbols',
error04: 'text for error04',
error05: 'text for error05',
error06: 'text for error06'
}
$scope.errorsArr = showErrorsWeWant;
console.log($scope.errorsArr);
}]);
myApp.service('showErrorsWeWant', [function (){
return ['error01', 'error04'];
}]);
Please let me know if I've missed something. Thank you.
You can use an ng-repeat to create an element with ng-message for each one:
<div ng-messages="myForm.myName.$error" style="color:red; padding-left: 60px;">
<div ng-message="{{key}}" ng-repeat="(key, errorMessage) in errors">{{ errorMessage }}</div>
</div>
For this to work, the keys of your errors object must match the type of error:
$scope.errors= {
required: 'You did not enter your name',
minlength: 'Your name is less than 5 symbols',
maxlength: 'Yr name is 6+ symbols'
};