I am having a problem with the dynamic creation of a Form. I have a directive that gets set against a form element. It uses Jquery to get the element by id. However it seems that it has not yet been added to the DOM.
<form class="form-horizontal">
<div class="control-group" ng-repeat="field in viewModel.fields">
<label class="control-label">{{field.label}}</label>
<div class="controls" ng-switch="field.type">
<input ng-switch-when="text" type="text" id="{{field.label}}" ng-model="field.data" validator="viewModel.validator" ruleSetName="personFirstNameRules"/>
<span ng-switch-when="text" validation-Message-For="{{field.label}}"></span>
</div>
</div>
<button ng-click="testID()">Submit</button>
</form>
If I hard code the ID attribute for the text field and on the span element validation-Message-For then their is no issue.The area where i am getting undefined is
var errorElementController = angular.element(errorElement).controller('ngModel');
var validatorsController = angular.element(errorElement).controller('validator');
The full directive is here
(function (angular, $) {
angular.module('directivesModule')
.directive('validationMessageFor', [function () {
return {
link: function (scope, element, attributes) {
var errorElementId = attributes.validationMessageFor;
if (!errorElementId) {
return;
}
var areCustomErrorsWatched = false;
var watchRuleChange = function (validationInfo, rule) {
scope.$watch(function () {
return validationInfo.validator.ruleSetHasErrors(validationInfo.ruleSetName, rule.errorCode);
}, showErrorInfoIfNeeded);
};
var watchCustomErrors = function (validationInfo) {
if (!areCustomErrorsWatched && validationInfo && validationInfo.validator) {
areCustomErrorsWatched = true;
var validator = validationInfo.validator;
var rules = validator.validationRules[validationInfo.ruleSetName];
for (var i = 0; i < rules.length; i++) {
watchRuleChange(validationInfo, rules[i]);
}
}
};
//alert(errorElementId);
// get element for which we are showing error information by id
var errorElement = $("#" + errorElementId);
console.log(angular.element(errorElement));
var errorElementController = angular.element(errorElement).controller('ngModel');
var validatorsController = angular.element(errorElement).controller('validator');
console.log(errorElementController);
console.log(validatorsController);
var getValidationInfo = function () {
return validatorsController && validatorsController.validationInfoIsDefined() ? validatorsController.validationInfo : null;
};
var validationChanged = false;
var subscribeToValidationChanged = function () {
if (validatorsController.validationInfoIsDefined()) {
validatorsController.validationInfo.validator.watchValidationChanged(function () {
validationChanged = true;
showErrorInfoIfNeeded();
});
// setup a watch on rule errors if it's not already set
watchCustomErrors(validatorsController.validationInfo);
}
};
var getErrorMessage = function (value) {
var validationInfo = getValidationInfo();
if (!validationInfo) {
return '';
}
var errorMessage = "";
var errors = validationInfo.validator.errors[validationInfo.ruleSetName];
var rules = validationInfo.validator.validationRules[validationInfo.ruleSetName];
for (var errorCode in errors) {
if (errors[errorCode]) {
var errorCodeRule = _.findWhere(rules, { errorCode: errorCode });
if (errorCodeRule) {
errorMessage += errorCodeRule.validate(value).errorMessage;
break;
}
}
}
return errorMessage;
};
var showErrorInfoIfNeeded = function () {
var validationInfo = getValidationInfo();
if (!validationInfo) {
return;
}
var needsAttention = validatorsController.ruleSetHasErrors() && (errorElementController && errorElementController.$dirty || validationChanged);
if (needsAttention) {
// compose and show error message
var errorMessage = getErrorMessage(element.val());
// set and show error message
element.text(errorMessage);
element.show();
} else {
element.hide();
}
};
subscribeToValidationChanged();
if (errorElementController)
{
scope.$watch(function () { return errorElementController.$dirty; }, showErrorInfoIfNeeded);
}
scope.$watch(function () { return validatorsController.validationInfoIsDefined(); }, subscribeToValidationChanged());
}
};
}]);})
(angular, $);
The error on the console is
TypeError: Cannot read property 'validationInfoIsDefined' of undefined
at subscribeToValidationChanged (http://localhost/trax/app/Directives/validationMessage.js:50:52)
at link (http://localhost/trax/app/Directives/validationMessage.js:103:24)
at nodeLinkFn (https://code.angularjs.org/1.2.13/angular.js:6271:13)
at compositeLinkFn (https://code.angularjs.org/1.2.13/angular.js:5682:15)
at publicLinkFn (https://code.angularjs.org/1.2.13/angular.js:5587:30)
at boundTranscludeFn (https://code.angularjs.org/1.2.13/angular.js:5701:21)
at Object.controllersBoundTransclude [as transclude] (https://code.angularjs.org/1.2.13/angular.js:6292:18)
at https://code.angularjs.org/1.2.13/angular.js:20073:32
at Array.forEach (native)
at forEach (https://code.angularjs.org/1.2.13/angular.js:304:11) <span ng-switch-when="text" validation-message-for="{{field.label}}" class="ng-scope">
you are writing Directive name as camel case when you are define. in this case angular read this directive as - based values
so validation-Message-For should be validation-message-for in your Html code
<span ng-switch-when="text" validation-message-for="{{field.label}}"></span>
and change the input id attribute value assigning type:
remove the {{}} from id attribute
<input ng-switch-when="text" type="text" id="field.label" ng-model="field.data" validator="viewModel.validator" ruleSetName="personFirstNameRules"/>
update
problem with ng-switch when. in your Plunker the input tags are not rendering as input field.
Be aware that the attribute values to match against cannot be expressions.
They are interpreted as literal string values to match against. For example,
ng-switch-when="someVal" will match against the string "someVal" not against the
value of the expression $scope.someVal.
refer this Question. StackOverflow Question
Updated Plunker
Related
I try to learn SAPUI5 with Samples frpm Demo kit Input - Checked. I get an error message: oInput.getBinding is not a function
I have a simple input field xml:
<Label text="Name" required="false" width="60%" visible="true"/>
<Input id="nameInput" type="Text" enabled="true" visible="true" valueHelpOnly="false" required="true" width="60%" valueStateText="Name must not be empty." maxLength="0" value="{previewModel>/name}" change= "onChange"/>
and my controller:
_validateInput: function(oInput) {
var oView = this.getView().byId("nameInput");
oView.setModel(this.getView().getModel("previewModel"));
var oBinding = oInput.getBinding("value");
var sValueState = "None";
var bValidationError = false;
try {
oBinding.getType().validateValue(oInput.getValue());
} catch (oException) {
sValueState = "Error";
bValidationError = true;
}
oInput.setValueState(sValueState);
return bValidationError;
},
/**
* Event handler for the continue button
*/
onContinue : function () {
// collect input controls
var that = this;
var oView = this.getView();
var aInputs =oView.byId("nameInput");
var bValidationError = false;
// check that inputs are not empty
// this does not happen during data binding as this is only triggered by changes
jQuery.each(aInputs, function (i, oInput) {
bValidationError = that._validateInput(oInput) || bValidationError;
});
// output result
if (!bValidationError) {
MessageToast.show("The input is validated. You could now continue to the next screen");
} else {
MessageBox.alert("A validation error has occured. Complete your input first");
}
},
// onChange update valueState of input
onChange: function(oEvent) {
var oInput = oEvent.getSource();
this._validateInput(oInput);
},
Can someone explain to me how I can set the Model?
Your model is fine and correctly binded.
The problem in your code is here, in the onContinue function
jQuery.each(aInputs, function (i, oInput) {
bValidationError = that._validateInput(oInput) || bValidationError;
});
aInput is not an array, so your code is not iterating on an array element.
To quickly fix this, you can put parentheses around the declaration like this:
var aInputs = [
oView.byId("nameInput")
];
Also, you could remove the first two lines of the _validateInput method since they are useless...
Usually, we set the model once the view is loaded, not when the value is changed. For example, if you would like to set a JSONModel with the name "previewModel", you can do as mentioned below.
Note that onInit is called when the controller is initialized. If you bind the model properly as follows, then the oEvent.getSource().getBinding("value") will return the expected value.
onInit: function(){
var oView = this.getView().byId("nameInput");
oView.setModel(new sap.ui.model.json.JSONModel({
name : "HELLO"
}), "previewModel");
},
onChange: function(oEvent) {
var oInput = oEvent.getSource();
this._validateInput(oInput);
},
...
Also, for validating the input text, you can do the following:
_validateInput: function(oInput) {
var oBinding = oInput.getBinding("value");
var sValueState = "None";
var sValueStateText = "";
var bValidationError = false;
if(oBinding.getValue().length === 0){
sValueState = "Error";
sValueStateText = "Custom Error"
}
oInput.setValueState(sValueState);
if(sValueState === "Error"){
oInput.setValueStateText(sValueStateText);
}
return bValidationError;
},
Please note that the code above is not high quality and production ready as it's a quick response to this post :)
I'm trying to perform multiple regex test on input filed.
Below the script:
$("#search-registration").keyup(function () {
var input_data = $('#search-registration').val();
var regexTest = function() {
this.withPrefix = /^[iI]-[a-zA-Z]{4}$/;
this.noPrefix = /^[a-zA-Z]{4}$/;
}
if(regexTest.withPrefix.test(input_data) || regexTest.noPrefix.test(input_data)) {
console.log(input_data);
$( "div.result" ).html(input_data);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="search-registration" name="regcode" class="form-control" placeholder="Search">
<div id="result">
</div>
I'm not able to perform the double regex and I get the following error:
Uncaught TypeError: Cannot read property 'test' of undefined
What am I doing wrong? Honestly I'm not able to figure out the issue.
Thanks
You need the 'new' keyword before function, like this:
var regexTest = new function() {
this.withPrefix = /^[iI]-[a-zA-Z]{4}$/;
this.noPrefix = /^[a-zA-Z]{4}$/;
}
Try using
var regexTest = Object({
withPrefix : "/^[iI]-[a-zA-Z]{4}$/",
noPrefix : "/^[a-zA-Z]{4}$/",
test : function (input_data) {
//test code here
}
});
Instead of
var regexTest = function() {
this.withPrefix = /^[iI]-[a-zA-Z]{4}$/;
this.noPrefix = /^[a-zA-Z]{4}$/;
}
Good day. I have read and done almost all of the solution in the questions but cant seem to solve my problem. As written in my question, in mvc, i am passing a value from controller to view a string and then get by javascript to run a modal if ever a certain condition is met. please help. thanks.
here is the code in my controller:
public ActionResult Series()
{
List<sample> series = db.samples.Where(x => x.status == "False").ToList();
if ( series.Count == 0)
{
ViewBag.Info = "None";
}
else {
ViewBag.Series = series;
ViewBag.Info = "Have";
}
return View();
}
My View:
<input type="text" value="#ViewBag.Info" id="info" name="info" />
My Javascript:
#section Scripts{
<script>
$(window).on('load', function () {
var modelll = document.getElementById("#(ViewBag.Info)").value;
var s_end = document.getElementById("myNumber2").value;
var s_current = document.getElementById("myNumber3").value;
var s_status1 = document.getElementById("status").value;
var s_id1 = parseInt(document.getElementById("myNumber").value);
var s_end2 = parseInt(s_end, 10);
var s_current2 = parseInt(s_current, 10);
var x = parseInt(s_current, 10) + 1;
document.getElementById("item1").value = s_id1;
document.getElementById("item2").value = s_end;
document.getElementById("item3").value = x;
document.getElementById("status2").value = s_status1;
if (modelll === 'Have')
{
if ((s_current2 > s_end2) && (s_current2 != s_end2)) {
$('#myModal').modal({ backdrop: 'static', keyboard: false });
$('#myModal').modal('show');
}
}
else
{
$('#myModal').modal({ backdrop: 'static', keyboard:false });
$('#myModal').modal('show');
}
});
</script>
}
getElementById need an ID but you are passing #ViewBag.Info. change it to :
var modelll = document.getElementById("info").value;
also you are making many extra variables which are not really needed. for example to get what you have in s_current2, you can use
var s_current = parseInt(document.getElementById("myNumber3").value, 10);
no need to create another variable to convert it to integer.
To get the value from textbox
var modelll = document.getElementById("info");
To set the value to textbox
document.getElementById("info").value = var modelll;
you are using #ViewBag.Info instead of element id.
Following line is causing the problem in your code :
var modelll = document.getElementById("#(ViewBag.Info)").value;
// document.getElementById needs Id but you are passing #(ViewBag.Info) which is wrong
var modelll = document.getElementById("info").value; //info id of your textbox
// now check
if (modelll === 'Have')
{ }
else
{ }
I have a simple form with a checkbox which clicked deletes a property from an object.
Here is the controller:
app.controller('PropController', function ($scope) {
var str = '{"meta":{"aprop":"lprop"},"props":{"gprop":12,"lprop":9,"wrop":5}}';
$scope.filecontent = JSON.parse(str);
$scope.delprop = false;
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('delprop', function () {
if ($scope.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
And the view:
<div ng-app="SomeProperties" ng-controller="PropController">
<div ng-if="proptodel">
there is a property to delete: {{proptodel}}
<form><input type="checkbox" ng-model="delprop"></form>
filecontent: {{filecontent}}
</div>
<div ng-if="!proptodel">
there is NO property to delete
</div>
</div>
The app on jsfiddle.
The problem appears when the form is in the ng-if, it stops behaving. As you can try it in the jsfiddle, when I delete ng-if="proptodel" from the div containing the form, it working normally. What is the explanation of this?
You need to put the delprop into in object to make ng-model work properly. That means your markup should have:
<form><input type="checkbox" ng-model="obj.delprop"></form>
And your Javascript code should look like:
$scope.obj = {
delprop: false
};
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('obj.delprop', function () {
if ($scope.obj.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
Of course you should find a proper name for the object as obj is really bad and generic ;-)
I'm using typeahead to get some suggestions on an input text, this is inside a div controlled by an Angular controller.
The code for the suggestion tasks works with a jQuery plugin, so when I select, something I'm trying to assign a value to $scope, however this is NEVER happening.
I already tried getting the scope of the element with var scope = angular.element($("#providersSearchInput").scope() and then assign it as suggested here but it didn't work.
This is what I'm trying:
<div class="modal-body" ng-controller="ProvidersController" ng-init="orderReviewTab = 'observations'">
<input type="text" id="providersSearchInput" data-provide="typeahead" class="form-control input-md" placeholder="Buscar proovedores">
{{currentProvider}}
</div>
The controller looks like this:
tv3App.controller('ProvidersController', function($scope, $rootScope, $http, $timeout) {
var resultsCache = [];
$("#providersSearchInput").typeahead({
source: function (query, process) {
return $.get("/search/providers/?query=" + query, function (results) {
resultsCache = results;
return process(results);
},'json');
},
matcher: function (item) {
var name = item.name.toLowerCase();
var email = item.email.toLowerCase();
var contact_name = item.contact_name.toLowerCase();
//console.log(name);
var q = this.query.toLowerCase();
return (name.indexOf(q) != -1 || email.indexOf(q) != -1 || contact_name.indexOf(q) != -1);
},
scrollHeight: 20,
highlighter: function (itemName) {
var selected = _.find(resultsCache,{name:itemName});
var div = $('<div></div>');
var name = $('<span ></span>').html('<strong style="font-weight:bold">Empresa: </strong> ' + selected.name);
var contact = $('<span ></span>').html(' <strong style="font-weight:bold">Contacto: </strong> ' + selected.contact_name);
var email = $('<span ></span>').html(' <strong style="font-weight:bold">e-mail:</strong> ' + selected.email);
return $(div).append(name).append(contact).append(email).html();
},
minLength: 3,
items: 15,
afterSelect: function (item) {
console.log(item);
$scope.$emit('providerSelected',item);
}
});
$scope.$on('providerSelected', function (event,provider) {
console.log(provider);
$scope.currentProvider = provider;
$scope.$apply();
});
});
Edit
I tried this to check any changes:
$scope.$watch('currentProvider',function (newValue,oldValue) {
console.log(oldValue);
console.log(newValue);
});
So when selecting something it actually triggers and $scope.currentProvider seems to be updated but its never getting rendered at view ...
get https://angular-ui.github.io/bootstrap/
once you do, in your code make sure
angular.module('myModule', ['ui.bootstrap']);
and for typeahead have
<input type="text" ng-model="currentProvider" typeahead="provider for provider in getProviders($viewValue) | limitTo:8" class="form-control">
In your controller make sure you have
$scope.getProviders = function(val){
return $http.get('/search/providers/?query=' + val).then(function(response){
return response.data;
})
}
This should do the trick although I haven't tested