I have an <input> box that acts as a search bar:
<input type="text" class="form-control input-lg" placeholder="Filter" ng-init="initSearch()" ng-model="search" ng-change="updateSearch()" id="search_bar">
and has the following accompanying angular code:
$scope.initSearch = function(){
var searchParam = parseQueryString()["searchParam"];
console.log(searchParam);
if (searchParam !== undefined){
var element = angular.element(document.querySelector('#search_bar'))[0];
console.log(element);
element.value = searchParam;
}
};
$scope.updateSearch = function(){
$location.search('searchParam',document.getElementById('search_bar').value);
};
The user has to be able to enter an URL with the searchParam already set and the page has to load the appropriate data. Once I change the value of the input box how would I get it to actually reflect that input in the data it displays? It only seems to update when the search parameter is entered into it manually. I've also tried changing the value without jQLite and just used document.getElementById etc
rather than look at the dom, why don't you use the actual model for your function like so:
<input
type="text"
class="form-control input-lg"
placeholder="Filter"
ng-init="initSearch(search)"
ng-model="search"
ng-change="updateSearch(search)"
id="search_bar">
Edit:
Expanding on my initial answer, you read the Angular $location params when the page loads. I think you were a little confused about ng-init; this directive just gives you a handy place to bind some data or run some function -- it doesn't specifically affect the model on this element. So just read the location in your controller and bind it to your model, and also have the model bind those changes to the location like so:
<div ng-controller="SearchCtrl as vm">
<input type="text"
class="form-control input-lg"
placeholder="Filter"
ng-model="vm.search"
ng-change="updateSearch(search)"
id="search_bar">
</div>
js:
var app = angular.module('myApp', []);
app.controller('SearchCtrl', function($location) {
vm.search = $location.search().searchParam;
vm.updateSearch = function() {
$location.search('searchParam', vm.search);
};
});
I ended up solving this by creating a custom directive that used ngModel directly alongside $setViewValue. Here is my directive.
app.directive('initSearch', function(){
return {
require: "?ngModel",
link: function(scope, element, attrs, ngModel){
var parseQueryString = function(){
var str = window.location.search;
var objURL = {};
str.replace(
new RegExp("([^?=&]+)(=([^&]*))?", "g" ),
function($0,$1,$2,$3){
objURL[$1] = $3;
}
);
return objURL;
};
var searchParam = parseQueryString()["searchParam"];
var searchBar = document.getElementById("searcher");
if(searchParam!==undefined && searchBar.value ===''){
ngModel.$setViewValue(searchParam);
searchBar.value = searchParam;
}
scope.onChange = function(){
ngModel.$setViewValue(scope.value);
}
}
};
});
Related
I have upload file feature and writing the filename inside input box, but when I upload file next time, the ng-model inside input won't update the filename as newer.How to update ng-model everytime I select new file. Here is the code.
JS:
$scope.setFile = function(element) {
$scope.$apply(function($scope) {
$scope.myFile = element.files[0];
$scope.FileName=$scope.myFile.name;
$scope.FileName = $scope.FileName.replace(/\..+$/, '');
$scope.fileExtension = element.files[0].name.split('.').pop();
console.log($scope.FileName);
console.log($scope.fileExtension);
});
};
HTML code:
<input type="file" name="upload" ng-model="diagram" onchange="angular.element(this).scope().setFile(this)" base-sixty-four-input>
<p>Tags:</p>
<p><input type="text" class="form-control input-sm" ng-model="FileName" ></p>
Any help is appreciated. Thanks
Can you please try this?? No need to pass $scope to apply.
$scope.setFile = function(element) {
$scope.$apply(function() {
$scope.myFile = element.files[0];
$scope.FileName=$scope.myFile.name;
$scope.FileName = $scope.FileName.replace(/\..+$/, '');
$scope.fileExtension = element.files[0].name.split('.').pop();
console.log($scope.FileName);
console.log($scope.fileExtension);
});
};
Don't use $scope.apply, but use the safer $timeout service:
$scope.setFile = function(element) {
$timeout(function(){
$scope.myFile = element.files[0];
$scope.FileName=$scope.myFile.name;
$scope.FileName = $scope.FileName.replace(/\..+$/, '');
$scope.fileExtension = element.files[0].name.split('.').pop();
console.log($scope.FileName);
console.log($scope.fileExtension);
}, 0);
};
This way, your bindings will be always up-to date with your events (and thus, your $scope.variable will be assigned).
If this does not fix your problem, you may have a problem with scopes and/or your variable is misassigned elsewhere.
I am hoping to get an input value inside a keyup function that can runs from multiple inputs. Every time there is a keyup the function will trigger according to the specific input. So, I am trying to use $this inside the function. No succes so far..
HTML code:
<input ng-keyup="getRxcui()" placeholder="Type med a" id="medicineA" />
<input ng-keyup="getRxcui()" placeholder="Type med b" id="medicineB" />
Angular code:
var rxConflicts = angular.module('rxConflicts', []);
rxConflicts.controller('MainController', function($scope, $http){
$scope.getRxcui = function(event){
// getting the value for each medicine input
var medValue = $(this).value;
console.log(medValue);
}
});
I am pretty sure $(this) is the right way to do this so that I don't need to duplicate that function for each input and use ng-model... You can take my word that the angular works fine.
Any help is appreciated. Thanks
use ng-model and pass it in function:
<input ng-keyup="getRxcui(medicineA)" ng-model="medicineA" placeholder="Type med a" id="medicineA" />
<input ng-keyup="getRxcui(medicineB)" ng-model="medicineB" placeholder="Type med b" id="medicineB" />
Angular code:
var rxConflicts = angular.module('rxConflicts', []);
rxConflicts.controller('MainController', function($scope, $http){
$scope.getRxcui = function(value){
// getting the value for each medicine input
var medValue = value;
console.log(medValue);
}
});
Angular 2 and superior:
You could pass the $event on the keyUp and use it to get the target (the input) and it's value. In case you're using formControls and not binding directly through ngModel
Template HTML:
<input (keyup)="getRxcui($event)">
Component.ts
getRxcui(event){
var inputValue = event.target.value;
console.log(inputValue);
}
It is possible make the required value dependet of some funcion?
Something like this? I want to do this because I want to change the required attribute to some form inputs...
HTML:
Name: <input type="text" ng-model="user.name" ng-required="isRequired('name')" />
Age: <input type="text" ng-model="user.age" ng-required="isRequired('age')" />
JS:
$scope.isRequired(fieldName){
$scope.requiredFields = [];
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
for (i in requiredFields) {
if (requiredFields[i] == fieldName){
return true;
}
}
return false;
}
Updated Answer:
So based on your updated OP, what you want is certainly doable. The problem with what you were trying to do is that ng-required has no ability to execute a function, it only reads a boolean. But we can dynamically create variables based on data from the server to automatically set fields to required:
Updated Plunker
<form>
Name: <input type="text" ng-model="user.test" ng-required="name" /><br/>
<input type="text" ng-model="user.name" ng-required="age" />
<br/>
<button type="submit">Submit</button>
</form>
Note that I put a $scope property for each input in the ng-required attribute. Now we can dynamically create that $scope property and set it to true if our data says we need to:
$scope.isRequired = function(){
$scope.requiredFields = [];
$http.get('fields.json')
.success(function(data){
$scope.requiredFields = angular.fromJson(data);
console.log($scope.requiredFields.required)
for (i = 0; i < $scope.requiredFields.required.length; i++) {
$scope[$scope.requiredFields.required[i]] = true
}
console.log($scope[$scope.requiredFields.required[0]]);
})
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
}
$scope.isRequired()
So it is iterating over an array of required fields received from the server, and then dynamically creating a $scope property for each one that is required, and setting it to true. Any field that has that $scope property in it's ng-required will be required now. Anything not dynamically created will just return false, and ng-required doesn't trigger.
Original answer:
Plunker
As Pratik mentioned, ng-required only accepts a Boolean value, but we can toggle the value of that with a function.
HTML
<form>
Name: <input type="text" ng-model="user.name" ng-required="isRequired" />
<br/><button ng-click="toggle()">Required: {{isRequired}}</button>
<button type="submit">Submit</button>
</form>
code:
$scope.isRequired = true;
$scope.toggle = function() {
$scope.isRequired = !$scope.isRequired;
}
I know this is a couple of years old and so AngularJS may have changed, but the accepted answer as it stands today isn't correct. You can very easily execute a function within ng-required, as it takes an expression, which can be a function. For example:
index.html
<div ng-controller="ExampleController" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs track by $index">
[ X ]
<code>{{expr}}</code> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
script.js
angular.module('expressionExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}]);
In script.js, a function addExp is defined and added to the scope, and then it's called in the ng-click directive of the a tag, which also takes an expression as its argument.
This code is taken directly from the AngularJS documentation on expressions. It doesn't use ng-require directly, but any directive that takes an expression will work the same. I have used the same syntax to use a function for ng-require.
Here's a jsfiddle example of what I'm trying to accomplish.
I'm trying to build a US phone number input where the view displays as (333) 555-1212, but the model binds to the numeric integer 3335551212.
My intention is to add custom validators to NgModelController which is why I have require: ng-model; there are simpler solutions without the isolate scope and NgModelController, but I need both.
You'll see an immediate error in the console: Error: Multiple directives [ngModel, ngModel] asking for 'ngModel' controller on: <input ng-model="user.mobile numeric" name="telephone" type="tel"> -- thought I was using an isolate scope here...
Thank you for looking #mimir137 but I appear to have solved it:
http://jsfiddle.net/hr121r18/8/
The directive was using replace: true, which ends up with this structure:
<form ng-controller="FooCtrl" class="ng-scope">
<p>Enter US phone number</p>
<input ng-model="user.mobile numeric" name="telephone" type="tel">
</form>
Both the template and the markup called for ng-model which led to the symptomatic error in the problem description. Once I removed that, it leads to this markup (note the wrapper element phone-number):
<form ng-controller="FooCtrl" class="ng-valid ng-scope ng-dirty ng-valid-parse" abineguid="BC0D9644F7434BBF80094FF6ABDF4418">
<p>Enter US phone number</p>
<phone-number ng-model="user.mobile" class="ng-untouched ng-valid ng-isolate-scope ng-dirty ng-valid-parse">
<input ng-model="numeric" name="telephone" type="tel" class="ng-valid ng-dirty ng-touched">
</phone-number>
</form>
But removing this required changes to $render; the elem passed into the link function is now phone-number and so you need to dig to grab the input inside it and set the value on that:
ngModel.$render = function () {
elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
};
There were a few other issues. $render() also needed to be called from the watcher.
Final:
var app = angular.module('myApp', []);
// i want to bind user.mobile to the numeric version of the number, e.g. 3335551212, but
// display it in a formatted version of a us phone number (333) 555-1212
// i am trying to make the directive's scope.numeric to have two-way binding with the controller's
// $scope.user.mobile (using isolate scope, etc.).
app.controller('FooCtrl', function ($scope) {
$scope.user = {
mobile: 3335551212
};
});
app.directive('phoneNumber', ['$filter', function ($filter) {
return {
restrict: 'E',
template: '<input ng-model="numeric" name="telephone" type="tel">',
require: 'ngModel',
scope: {
numeric: '=ngModel'
},
link: function (scope, elem, attrs, ngModel) {
// update $viewValue on model change
scope.$watch('numeric', function () {
ngModel.$setViewValue(scope.numeric);
ngModel.$render();
});
// $modelValue convert to $viewValue as (999) 999-9999
ngModel.$formatters.push(function (modelValue) {
return $filter('phonenumber')(String(modelValue).replace(/[^0-9]+/, ''));
});
// $viewValue back to model
ngModel.$parsers.push(function (viewValue) {
var n = viewValue;
if (angular.isString(n)) {
n = parseInt(n.replace(/[^0-9]+/g, ''));
}
return n;
});
// render $viewValue through filter
ngModel.$render = function () {
elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
};
}
};
}]);
app.filter('phonenumber', function () {
return function (number) {
if (!number) {
return '';
}
number = String(number);
var formattedNumber = number;
var c = (number[0] === '1') ? '1 ' : '';
number = number[0] === '1' ? number.slice(1) : number;
var area = number.substring(0, 3),
exchange = number.substring(3, 6),
subscriber = number.substring(6, 10);
if (exchange) {
formattedNumber = (c + '(' + area + ') ' + exchange);
}
if (subscriber) {
formattedNumber += ('-' + subscriber);
}
return formattedNumber;
}
});
HTML
<form ng-controller="FooCtrl">
<p>Enter US phone number</p>
<phone-number ng-model='user.mobile'></phone-number>
</form>
I created this fiddle that gets rid of most of your errors coming up in the console. Hopefully this will at least be able to put you on the right track.
I changed the template so that you can see that the filter is actually working.
It now has the typical {{ngModel | FilterName}} in plain text underneath the textbox.
The only real issue is displaying it in the textbox. I'm sure you will have no problem with that. I will check in the morning just in case you still have questions regarding this.
Edit: Alright it appears you have solved it already. Great job!
I'm fairly new using AngularJS but I've been using for a pet project and I've run in to an issue. What I basically want to do is take the text input from this input field:
<form id="ci_search_form">
<p class="input-append"><label>Search:</label> <input type="text" id="query" ng:model="query" autofocus> <button ng:click="clearSearch()" class="btn"><i class="icon-remove"></i></button></p>
</form>
and update this input field's value with that value:
<div><input type="text" id="ciquery" ng:model="ciquery.Name"></div>
The second input filters some data and I can type in that directly and it works. However this page will have different sets of data, each with their own search input that I want updated by the master input at the top. I can't set value="" or use jQuery to set the value either, it just appears blank unless I explicitly type in that second input field. Can anyone assist with a solution?
EDIT
I thought I should include my app and controller code:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.clearSearch = function(){
$scope.query = '';
}
});
EDIT 2
Made some progress. Created a function that can be called an update ciquery in $scope:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$scope.ciquery = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.queryUpdate = function(){
$scope.ciquery = $scope.query;
}
$scope.clearSearch = function(){
$scope.query = '';
$scope.queryUpdate();
}
});
This works great. However, this creates another issue. Before in ciquery I was using ciquery.Name to filter only on the Name attribute. With this new solution I had to change it to this:
<div><input type="hidden" id="ciquery" ng:model="ciquery"></div>
This searches all fields in my data which returns unwanted results. Suggestions?
$scope and ng-model are differents. You should give ng-model's property to ng-click's function. Looks at this -> Ng-model does not update controller value
To update second input's field (here an example -> http://jsfiddle.net/yEvSL/1/)
<div><input type="text" id="ciquery" ng:model="query"></div>