Could not get input data from modal pop up using Angular.js - javascript

I am using the modal pop up where my form is present and I am unable to get the form data via ng-model using Angular.js. I am providing my code below.
<modal title="Owner Information" visible="showModal">
<form class="ng-pristine ng-valid" id="frmsignup" name="frmsignup" autocomplete="off">
<div class="input-group bmargindiv1 col-lg-4 col-md-4 col-sm-4 col-xs-12 plr-15">
<span class="input-group-addon ndrftextwidth text-left">Status:</span>
<select class="form-control" name="status" id="status" ng-model="status" required="required">
<option value="">Select Status</option>
<option value="1">Active</option>
<option value="0">Inactive</option>
</select>
</div>
<div class="input-group bmargindiv1 col-lg-4 col-md-4 col-sm-4 col-xs-12 plr-15">
<span class="input-group-addon ndrftextwidth text-left">Comment:</span>
<textarea rows="5" cols="50" class="form-control" id="comment" name="comment" ng-model="comment" required="required">
</textarea>
</div>
<input type="button" class="btn btn-success" ng-click="updateOwnerData();" id="addProfileData" value="Save" />
</form>
</modal>
My modal pop up is given below.
var dept=angular.module('cab');
dept.controller('ownerviewController',function($scope,$http,$timeout,$state,Upload,$window,DataService){
$scope.updateOwnerData=function(){
console.log('data',$scope.status,$scope.comment);
}
})
dept.directive('modal', function () {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog modal-lg">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace:true,
scope:true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value){
if(value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
The above is my script part. Here My issue is I could not get value through $scope from pop up window. I need to collect the value via Angular.js Scope.

I failed to figure out what is the problem with scopes. It seems that values are propagated inside (so, you can set the initial value for ng-model) but they do not come outside, so I've used controllerAs syntax and view model principle:
dept.controller('ownerviewController',function($scope){
var vm = this; // Creating view model
$scope.openPopUP=function(){
$scope.showModal = !$scope.showModal;
}
$scope.updateOwnerData=function(){
console.log('data', vm.status, vm.comment); //Showing data from view model
}
})
Next step, you should define view model in your template by means of controllerAs syntax and change ng-model bindings:
<body ng-controller="ownerviewController as vm">
...
<select class="form-control" name="status" id="status" ng-model="vm.status" required="required">
...
You can find the working example here
The full version with modal popup is also available

scopes
In the modal pop-up directive both transcluded: true and scope: true create their own isolated scope. The scope you want to get the updated inputs is yet another: your controller's scope.
See visual explanation in Access Parent Scope in Transcluded Directive.
communication
In order to communicate from inside the directive/transcluded-form with the parent's scope you can use the following:
add an own scope scope: { status: '=', comment: '=' } to your directive and use two-way-binding '=' to pass the parent's scope-variables like <modal title="Owner Information" visible="showModal" data-status="status", data-comment="comment">
create and inject a factory or service to handle communication (i.e. data-updates) between directive (form) and controller
See AngularJS : Directive transcluded scope lost
solution with (inherited) scope
see fiddle.
It just uses the parent scope (from controller) via prototypical inheritance.
So the model (status, comment) can be used as well as the function to update can be called within the transcluded form.

Related

My bootbox.js confirm dialogue requires two clicks to save

In order to display two input fields in a bootbox.confirm box, I've embedded an HTML form in the message field. Everything works fine, but if I enter text in the textarea, the Save button loses focus, and two clicks on the save button are required to execute save and clear the modal. The problem is exterior to the code below, though. This jsfiddle functions just fine with one click. I can't practically share the thousands of lines of codes this sits in, anyone know what might be causing this and how I can fix it?
bootbox.confirm({
title: "Save Foo",
message: '<div class="row"> ' +
'<div class="col-md-12"> ' +
'<div class="text-center">Save</div>' +
'<form class="form-horizontal"> ' +
'<div class="form-group"> ' +
'<label class="col-md-4 control-label" for="Question">Question</label> ' +
'<div class="col-md-4"> ' +
'<input id="name" name="name" type="text" value="Question" class="form-control input-md"> ' +
'<span class="help-block">You can edit your question before saving</span> </div> ' +
'</div> ' +
'<div class="form-group"> ' +
'<label class="col-md-4 control-label" for="notesbox">Notes:</label> ' +
'<div class="col-md-4"> <div class="textarea"> <label for="notesbox"> ' +
'<textarea name="notesbox" id="notesbox" rows="10" cols="30"></textarea></form></div> ' +
'</label> ' +
'</div>' +
'</div> ' +
'</div> </div>' +
'</form> </div> </div>',
buttons: {
'cancel': {
label: 'Don\'t save',
className: 'btn-danger pull-left'
},
'confirm': {
label: 'Save',
className: 'btn-success pull-right',
}
},callback: function (result) { if (result == true)
{ alert('Success')}
}
}
);
I'd start by using a script template, rather than using string concatenation to build your message - it would make it obvious that your current message has some invalid markup, which isn't doing you any favors. Here's one way of doing that:
<script type="text/template" id="form-template">
<div class="text-center">Save</div>
<form class="form-horizontal">
<div class="form-group">
<label class="col-md-4 control-label" for="Question">Question</label>
<div class="col-md-4">
<input id="name" name="name" type="text" value="Question" class="form-control input-md">
<span class="help-block">You can edit your question before saving</span>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="notesbox">Notes:</label>
<div class="col-md-4">
<div class="textarea">
<textarea class="form-control" name="notesbox" id="notesbox" rows="10" cols="30"></textarea>
</div>
</div>
</div>
</form>
</script>
The type="text/template" attribute on the script tag means that your browser won't treat the contents of the tag as JavaScript to be executed. You can pretty much use just about anything there, but text/template conveys the meaning pretty well, so I stick with that.
With that template tag, you can then get the message for your dialog by doing something like this:
let message = $('#form-template').html();
With that in place, I'd update your Bootbox usage to use the bootbox.dialog helper, rather than try to use bootbox.confirm for something it wasn't intended for. Here's your code, updated:
let message = $('#form-template').html();
let msgbox = bootbox.dialog({
title: "Save Foo",
message: message,
buttons: {
'cancel': {
label: "Don't save",
className: 'btn-danger pull-left'
},
'confirm': {
label: 'Save',
className: 'btn-success pull-right',
callback: function () {
let form = msgbox.find('form');
if(form.valid()){
alert('Valid!');
msgbox.modal('hide');
}
return false;
}
}
}
});
When using the dialog helper, the global callback is no longer executed; rather, each button would have it's own callback, as shown. In this example, I have return false; as the last line, so that the modal will not close automatically. This lets me validate the form (here, I'm assuming jQuery Validate is in use) and whatever else I wanted to do (such as submit the form via AJAX, etc.). Then, we use Bootstrap's modal() function to dismiss our dialog.

Text field displays value but doesn't catch it

I am working on the project that needs to be updates with some functions. One is where i need to update EAV registration form and make choose option, where i have 2 radio buttons and text field. When I click on one of the radio buttons, it takes the value and places it in the input textbox. The problems starts when i try to save registration. This text field attributes are saved in database where one of them is "isRequired". I can't save form because textfield asks to type something in it, but there is already a value. When I disable "isRequired" it saves the form, but there is no value saved in database. When I type any symbol next to radio button value required field disappears and then I can save the value in database. That's why my question is why field can't catch the value. I will put some of the code in this question because I can't make test environment. Have only files on the server. Hope someone can answer or give some clues what to do. I have opinions that this problem might be cause by keypress events, angularjs, jquery or EAV model.
Image: https://postimg.org/image/j8mgjia1d/
Creating fields:
backendComponents.directive('eavFormatted', function($compile)
{
return {
restrict: "E",
scope: true,
replace: true,
transclude: true,
template: '<div class="form-group field_eav field_eav_{{ config.ID }} field_eav_{{ config.handle }}"><label class="control-label">{{ config.name }}</label><div ng-transclude></div></div>',
link: function(scope, element, attrs)
{
var config = JSON.parse(attrs.config);
scope.config = config;
delete attrs.config;
element.removeAttr('ng-transclude');
}
}
});
backendComponents.directive('eavField', function($compile, $timeout) {
return {
restrict: "E",
scope: true,
replace: true,
link: function(scope, element, attrs)
if (html) {
var fieldName = 'eav_' + config.ID;
if (config.isRequired) {
html = html + '<div class="text-danger" ng-show="isSubmitted && eavform.' + fieldName + '.$error.required">Lūdzu aizpildiet šo lauku</div>';
}
html = '<div><ng-form name="eavform">' + html + element.html() + '</ng-form></div>';
var newElem = angular.element(html);
var attrElem = input ? newElem.find(input) : newElem;
attrElem.attr('ng-model', 'vals.eav.' + config.ID);
attrElem.addClass('form-control');
attrElem.attr('placeholder', config.description);
attrElem.attr('name', fieldName);
if (config.isRequired) {
attrElem.attr('ng-required', true);
}
}
}
}
Fields from inspect element from browser:
<div class="form-group field_eav field_eav_2 field_eav_epasts" config="{"ID":2,"eavFieldGroupID":null,"classID":2,"stringIdentifier":null,"name":"E-pasts","description":"E-PASTS *","type":3,"dataType":1,"position":1,"handle":"epasts","isMultiValue":null,"isRequired":1,"isDisplayed":null,"isDisplayedInList":null,"valuePrefix":null,"valueSuffix":null,"valueFieldID":null,"fieldName":"specField_2"}">
<label class="control-label ng-binding">E-pasts</label>
<div ng-transclude="">
<div class="ng-scope">
<ng-form name="eavform" class="ng-pristine ng-invalid ng-invalid-required">
<input type="text" ng-model="vals.eav.2" class="form-control ng-pristine ng-invalid ng-invalid-required" placeholder="E-PASTS *" name="eav_2" ng-required="true" required="required">
<div class="text-danger ng-hide" ng-show="isSubmitted && eavform.eav_2.$error.required">Lūdzu aizpildiet šo lauku</div>
</ng-form>
</div>
</div>
</div>
<div ng-transclude="">
<div class="ng-scope">
<ng-form name="eavform" class="ng-pristine ng-invalid ng-invalid-required">
<input type="text" ng-model="vals.eav.2" class="form-control ng-pristine ng-invalid ng-invalid-required" placeholder="E-PASTS *" name="eav_2" ng-required="true" required="required">
<div class="text-danger ng-hide" ng-show="isSubmitted && eavform.eav_2.$error.required">Lūdzu aizpildiet šo lauku</div>
</ng-form>
</div>
</div>
Code from the file
<eav-formatted config="[[ eavFieldsHandle.epasts.toJson() ]]">
<eav-field></eav-field>
</eav-formatted>
<legend style="padding-top: 0px;">Izvēlieties piegādes veidu: </legend>
<input type="radio" class="input" name="radio-1" id="radio-1" value="Option1">
<span><b>Choose 1</span>
<input type="radio" class="input" name="radio-1" id="radio-2" value="Option2">
<span><b>Choose 2</span>
Script of the file
$( function() {
$('input[name="radio-1"]').on('change', function() {
$('input[name="eav_2"]').val($(this).val());
});
} );

Searching through JSON Object with ng-disabled (AngularJS)

One of the features of my web application is the possibility to add new users (username + password) through a form. Thereby, I have one JSON object (l_usernames) defined in a controller (UsersController) with all the usernames already chosen by users to avoid the repetition of usernames (it's a unique key).
Sample of my data (fetched-data.json) - format of object "usernames" (l_usernames):
[{"0":"default","USERNAME":"default"},{"0":"user1","USERNAME":"user1"},{"0":"user2","USERNAME":"user2"},{"0":"user3","USERNAME":"user3"}]
There is a sample of the form to add new users (add-user.html):
<div class="row" ng-controller="UsersController">
<div class="col-md-12">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Add New User</h3>
</div>
<div class="panel-body">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="inputUserUsername" class="col-sm-2 control-label"><i class="icon fa fa-user"></i> USERNAME</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputUserUsername" placeholder="Username" ng-model="user_username">
</div>
</div>
<div class="form-group">
<label for="inputUserPassword" class="col-sm-2 control-label"><i class="icon fa fa-key"></i> PASSWORD</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="inputUserPassword" placeholder="Password" ng-model="user_password">
</div>
</div>
</form>
</div>
</div>
<form class="form-inline">
<div class="span7 text-center">
<button type="submit" class="btn btn-success" ng-click="addUser()" ng-disabled="(!user_username || !user_password)">Save</button>
</div>
</form>
</div>
</div>
Sample of my controller (userscontroller.js):
var app = angular.module('myApp');
app.controller('UsersController', ['$scope', 'services', function($scope, services) {
services.getData().then(function(data){
$scope.l_usernames = data.data;
});
}])
.factory('services', ['$http', function($http){
var serviceBase = 'services/'
var object = {};
object.getData = function(){
return $http.get('fetched-data.json');
};
return object;
}]);
I would like to know how it is possible to not allow the insert of new users if the username is already chosen - searching through the JSON object l_usernames - with ng-disabled (by disabling the "Save" button). I also want to print a simple message - "Username already chosen" - if such situation occurs. Thank you.
Add a watch on the user_username scope variable. Whenever it changes search through the JSON object, you can use lodash or underscorejs to search through l_usernames to see if the username already exists. If it exists then set a variable in the scope to false. Bind the ng-disabled of the save button to this variable. Use debounce on the user_username for better performance.
Take a look at this fiddle here
Controller
function UsersController($scope) {
$scope.name = 'Superhero';
$scope.l_username = [{"0":"default","USERNAME":"default"},{"0":"user1","USERNAME":"user1"},{"0":"user2","USERNAME":"user2"},{"0":"user3","USERNAME":"user3"}];
$scope.allowSave = true;
$scope.$watch('user_username', function(value) {
if (_.findWhere($scope.l_username, {"USERNAME": value}) !== undefined)
$scope.allowSave = false;
else
$scope.allowSave = true;
})
}
HTML
<button type="submit" class="btn btn-success" ng-click="addUser()" ng-disabled="!allowSave">Save</button>
Whenever the entered username is found in the array, the allowSave variable is changed which disables the 'save' button.
Note: I have used underscore.js to search through the list. You can use you custom method as well.
I have added the warning message and debounced the model for better performance.
I would make a validation directive.
HTML:
<input username-exists type="text" ng-model="userName" ng-model-options="{updateOn: 'default blur', debounce: { 'default': 700, 'blur': 0 }}" />
<div ng-if="myFormName.$error.usernameExists">Username exists!</div>
<button type="button" ng-disabled="myFormName.$invalid">
The ng-model-options is so that your model doesn't go crazy and update always (it delays the validation).
Javascript:
app.directive('usernameExists', function() {
return {
restrict: 'A', //match attributes only
require: 'ngModel',
scope: {
l_usernames: '='
},
link: function(scope, elem, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
//first, assume the model is valid until proven otherwise
ctrl.$setValidity('usernameExists', true);
if(viewValue.length > 0 && !ctrl.$error.usernameExists) {
for(var i = 0; i < scope.l_usernames.length; ++i) {
if(scope.l_usernames[i].USERNAME === viewValue) {
//username exists, so set valididty to false
//the form is not valid
ctrl.$setValidity('usernameExists', false);
break; //found match
}
}
}
return viewValue;
});
}
};
})

Creating a directive with a dynamic ng-options

Okay, so here's my custom directive:
angular.module('bulwarkWebControls', [])
.directive('dropdownList', [
function() {
return {
scope: {
label: '#', // optional
changeCallback: '&',
options: '=',
required: "=",
disabled: "=",
id: "=",
name: "=",
model: "=",
value: "=",
display: "="
},
restrict: 'E',
replace: true, // optional
templateUrl: 'app/templates/dropDownList.html',
link: {
pre: function (scope, element, attr) {
scope.expression = "o."+value +" as o."+display+" for o in options";
}
}
};
}
]);
Template:
<div class="row form-group form-horizontal">
<label data-for="id" class="control-label col-md-3">{{label}}</label>
<div class="col-md-9">
<select data-id="id" data-name="name" data-ng-disabled="disabled" class="form-control"
data-ng-model="model"
data-ng-options="{{expression}}" data-ng-required="required">
<option></option>
</select>
</div>
Html code that utilizes the directive:
<div>
<dropdown-list data-label="Phone(s)" data-id="phoneList" data-name="phoneList"
data-disabled="vm.workOrder.Contacted"
data-model="vm.workOrder.PhoneNumber_Id" data-value="Id" data-display="Number"
data-options="vm.workOrder.CustomerPhoneNumbers" data-required="vm.workOrder.SpokeTo_Id!=5" />
</div>
What I am trying to do is basically create the expression for the ng-options dynamically at run-time based on the "display" and "value" parameters that I am passing to the directive. You can see that in the "pre:" linking function inside the directive. Now, I know that this is not working because at the time this function is being executed I do not have the scope values. However, I cannot do this in the post: linking because that would be too late for the ng-options expression. Is there a way to achieve this functionality or am I totally barking up the wrong tree here? Thank you so much in advance.
Never mind. I used the following code in the template:
<div class="row form-group form-horizontal">
<label data-for="id" class="control-label col-md-3">{{label}}</label>
<div class="col-md-9">
<select data-id="id" data-name="name" data-ng-disabled="disabled" class="form-control"
data-ng-model="model"
data-ng-options="o.{{value}} as o.{{display}} for o in options" data-ng-required="required" compile>
<option></option>
</select>
</div>
That, and I took whatever code I had originally put in the pre: linking function inside the directive.

$scope doesn't picks up string from form input - AngularJS, JS

I am trying to implement Change Password feature in MVC (Rest server) application from the User Control Panel but because of some strange reason I can't scope values from form input.
My html form:
<accordion-group heading="Change password" is-open="changePasswordStatus.open" style="cursor: pointer">
<div>
<div>
<form class="form-horizontal" role="form">
<form-row model="newPassword" name="New: " size="col-sm-8"></form-row>
<form-row model="repeatedNewPassword" name="Repeat: " size="col-sm-8"></form-row>
<form-row model="currentPassword" name="Current: " size="col-sm-8"></form-row>
<br>
</form>
</div>
<div>
<button class="btn btn-default btn-sm" ng-click="changePassword()">Save</button>
<button class="btn btn-warning btn-sm" ng-click="changePasswordStatus.open = !changePasswordStatus.open">Cancel</button>
</div>
</div>
</accordion-group>
My formRow.html:
<div class="form-group">
<label for="inputText3" class="col-sm-2 control-label">{{name}}</label>
<div class="{{size}}">
<input type="{{type}}" class="form-control" data-ng-model="model">
</div>
</div>
My formRow.js:
collectionsApp.directive('formRow', function(){
return {
restrict: 'E',
replace: true,
scope: {
model: '=',
name: '#',
size: '#',
type: '#'
},
templateUrl: '/directives/formRow.html',
link: function(scope, attrs, element) {
}
}
});
My userController:
$scope.changePassword = function() {
if ($scope.newPassword === $scope.repeatedNewPassword) {
userService.changePassword($scope.newPassword, $scope.currentPassword);
} else {
$scope.alerts.push({
msg : 'Passwords do not match!'
})
}
}
And when I enter values in inputs and place breakpoints and trigger changePassword() in debug i get:
If condition has passed with value of true because they are both undefined.
I believe this may be the case of prototypical inheritance and scope, requiring an object being passed into your scoped parameters. Mind trying to change your parent scope to use an object and bind to the properties and not the primitive values:
$scope.security = {newPassword : '', currentPassword = ''};
then you would use something like this in your attributes:
model="security.newPassword"
Or better yet, not make it confusing with model:
myapp-model="security.newPassword"
or pass in the whole object
myapp-security="security"
Working in this plunker template ?
<form ...>
<form-row model="newPassword" name="New: " size="col-sm-8" required ></form-row>
<form-row model="repeatedNewPassword" name="Repeat: " size="col-sm-8" required ></form-row>
<form-row model="currentPassword" name="Current: " size="col-sm-8" required ></form-row>
</form>

Categories

Resources