Angularjs Form $valid not update - javascript

I have a custom directive that is an ng-modal window. My issue is when I set one of the fields(patientId) on show in code, the form's $valid won't update to true even tho all the required fields are true. When I updated the patientid field thru the UI, $valid updates correctly. Since the field in question is disabled in current cases, I can't rely on the user manually updated the field. As a quick fix I used the $error.required for the disable for the Save button but want to do it the correct way.
'use strict';
var mod
try {
mod = angular.module('DCI');
}
catch (err) {
mod = angular.module('DCI', []);
}
mod.directive('labResultEntry', function () {
return {
restrict: 'E',
scope: {
labRanges: '=',
show: '=',
patientList: '=',
editResult: '=',
saveLabCallback: '='
},
replace: true,
link: function (scope, element, attrs) {
scope.dialogStyle = {};
scope.result = {};
scope.autoComplateControl1 = {};
scope.autoComplateControl2 = {};
scope.result.SensitiveData = 'N';
scope.editdisable = scope.isOpen = false;
var rootScope = scope.$parent;
if (attrs.saveResultCallback)
scope.saveResultCallback = attrs.saveResultCallback
if (attrs.width)
scope.dialogStyle.width = attrs.width;
if (attrs.height)
scope.dialogStyle.height = attrs.height;
scope.$watch('show',
function () {
if (scope.show == true) {
if (scope.editResult != undefined) {
scope.editdisable = true;
scope.autoComplateControl1.insertInput(rootScope.patientName);
scope.result.patientId = rootScope.patientId;
scope.result.sampledate = scope.editResult.sampledate;
scope.result.TestCode = scope.editResult.TestCode
scope.result.Result = parseFloat(scope.editResult.Result);
scope.result.LabResultId = scope.editResult.LabResultId;
angular.forEach(scope.labRanges, function (test) {
if (test.TestCode == scope.editResult.TestCode) {
scope.result.TestDescription = test.TestDescription;
scope.result.ShortName = test.ShortName;
scope.result.MaxValue = test.MaxValue;
scope.result.MinValue = test.MinValue;
scope.result.UOM = test.UOM;
scope.autoComplateControl2.insertInput(test.TestDescription);
}
})
}
else
scope.editdisable = false;
SetPatientId();
}
}, true);
function SetPatientId() {
if (rootScope.patientId) {
scope.autoComplateControl1.insertInput(rootScope.patientName);
rootScope.safeApply(function(){
scope.result.patientId = rootScope.patientId;
});
}
else {
if (scope.autoComplateControl1.clearnInput != undefined) {
scope.autoComplateControl1.clearnInput();
}
scope.result.patientId = undefined;
}
};
function reset() {
scope.result = {};
scope.result.SensitiveData = 'N';
SetPatientId();
scope.autoComplateControl2.clearnInput();
scope.editResult = undefined;
};
scope.hideModal = function () {
reset();
scope.show = false;
};
scope.autoCompleteSelect = function (item) {
if (item) {
scope.result.MaxValue = item.description.MaxValue;
scope.result.MinValue = item.description.MinValue;
scope.result.UOM = item.description.UOM;
scope.result.ShortName = item.description.ShortName;
scope.result.TestCode = parseFloat(item.description.TestCode, 10);
scope.result.TestDescription = item.description.TestDescription;
}
};
scope.open = function ($event) {
$event.preventDefault();
$event.stopPropagation();
scope.isOpen = true;
};
scope.selectPatient = function (item) {
if (item) {
var found = false;
angular.forEach(scope.patientList, function (itemp) {
if (item.originalObject.PatientId = itemp.PatientId)
found = true;
});
if (found)
scope.result.patientId = item.originalObject.PatientId;
}
};
scope.LookUpTestCode = function () {
angular.forEach(scope.labRanges, function (test) {
if (test.TestCode == scope.result.TestCode) {
scope.result.TestDescription = test.TestDescription;
scope.result.ShortName = test.ShortName;
scope.result.MaxValue = test.MaxValue;
scope.result.MinValue = test.MinValue;
scope.result.UOM = test.UOM;
scope.autoComplateControl2.insertInput(test.TestDescription);
}
})
};
scope.saveResult = function () {
var result = {};
angular.copy(scope.result, result);
result.labLocation = "002060";
scope.saveLabCallback(result);
scope.hideModal()
};
},
template: "HTML code below as single string"
<div class="ng-modal colored-header" ng-show="show">
<div class="ng-modal-overlay" ng-click="hideLabModal()"></div>
<div class="ng-modal-dialog md-content" ng-style="dialogStyle">
<div class="modal-header">
<div class="ng-modal-close" ng-click="hideModal()">X</div>
<h3>Lab Result</h3>
</div>
<div class="ng-modal-dialog-content">
<form name="labEntry" role="form" class="modal-body">
<div angucomplete-alt id="ex2" placeholder="Patient*" maxlength="50" pause="400" selected-object="selectPatient" local-data="patientList" field-required="!result.patientId"
field-required-class="ng-invalid" search-fields="PatientName" disable-input="editdisable" title-field="PatientName" minlength="4" input-class="form-control-small form-control" match-class="highlight" control="autoComplateControl1" />
<br />
<input class="form-control col-xs-9 col-sm-9 col-md-9" style="margin-top: 3px; margin-bottom: 3px;" type="text" ng-disabled="true" ng-model="result.labLocation" placeholder="OTHER (LAB)" />
<br />
<br />
<br />
<input ng-style="{ 'border-color' : (labEntry.TestCode.$valid == false ? 'red' : 'null') }" name="TestCode" class="form-control col-xs-9 col-sm-9 col-md-9" ng-disabled="editdisable" ng-required="!result.TestCode" ng-model="result.TestCode" placeholder="Test code*" ng-blur="LookUpTestCode()" />
<br />
<br />
<br />
<div angucomplete-alt id="ex3" placeholder="Description*" maxlength="50" pause="400" selected-object="autoCompleteSelect" local-data="labRanges"
search-fields="TestDescription" disable-input="editdisable" title-field="TestDescription" minlength="4" input-class="form-control form-control-small" match-class="highlight" control="autoComplateControl2" />
<br />
<input ng-style="{ 'border-color' : (labEntry.Result.$valid == false ? 'red' : 'null') }" style="margin-top: 3px; margin-bottom: 3px;" name="Result" class="form-control col-xs-9 col-sm-9 col-md-9" ng-required="!result.Result" ng-model="result.Result" placeholder="Result*" />
<br />
<br />
<br />
<p class="input-group">
<input name="sdate" ng-style="{ 'border-color' : (labEntry.sdate.$valid == false ? 'red' : 'null') }" class="input-group-addon form-control" is-open="isOpen" datepicker-popup="MM/dd/yyyy" ng-required="!result.sampledate" ng-model="result.sampledate"
placeholder="Sample Date*" />
<span class="input-group-btn">
<span class="input-group-addon btn btn-primary" ng-click="open($event)"><i class="glyphicon glyphicon-th"></i></span>
</span>
</p>
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.MinValue" placeholder="Range Min" />
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.MaxValue" placeholder="Range Max" />
<br />
<br />
<input class="col-xs-6 col-sm-6 col-md-6" type="text" ng-disabled="true" ng-model="result.UOM" placeholder="UOM" />
<br />
<br />
<input type="checkbox" class="iCheck" icheck ng-model="result.SensitiveData" ng-true-value="'Y'" ng-false-value="'N'" /> Sensitive Data
<br />
<br />
<textarea class="form-control" rows="4" placeholder="comments..." ng-model="result.Comment"></textarea>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-flat md-close" ng-click="hideModal()">Cancel</button>
<button type="button" class="btn btn-flat btn-success" ng-disabled="!labEntry.$valid" ng-click="saveResult()">Save</button>
</div>
</div>
</div>
</div>

The digest() method might help:
add this function to the end and call it from any function that changes values to the scope after everything is set:
function digest() {
if ( scope.$$phase !== '$apply' && scope.$$phase !== '$digest' ) {
scope.$digest();
}
}
You can get more Info on the digest function on Angulars Website:
Processes all of the watchers of the current scope and its children.
Because a watcher's listener can change the model, the $digest() keeps
calling the watchers until no more listeners are firing.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest
I hope this helps.

Figured it out. It was an issue with Autocomplete-alt directive I was using. Updated to 1.1.0 and it solved it.

Related

jQuery autocomplete not working

I am using jQuery-UI autocomplete on angular controller.
On the server side I have MVC, C# 6.0.
Autocomplete simply doesn't work, nothing shows up. I've checked with debugger how many results are returned from server - results are returned:
But nothing happens on the GUI. No drop down list showed up, nothing. No error in the console.
Here is angular controller / function:
angular.module("calendarDefinitionModule")
.controller("calendarDefinitionController", ["$scope", "$http", function ($scope, $http) {
$scope.UrlDeliveryListPaging = null;
$scope.SearchResults = null;
$scope.SearchDishSemiDishMerc = function (srt) {
if ($(event.currentTarget) === null || $(event.currentTarget).val().length < 3) {
return;
}
var objTrigger = event.currentTarget;
$http({
method: "POST",
url: $scope.UrlDeliveryListPaging,
data: {
cSEARCH_STRING: $(event.currentTarget).val(),
cSEARCH_DISH: srt === 'dish' ? '1' : null,
cSEARCH_SEDI: srt === 'semidish' ? '1' : null,
cSEARCH_MERC: srt === 'merc' ? '1' : null
}
}).then(function success(response) {
if (response.data === null) {
return;
}
$scope.SearchResults = [];
var i;
for (i = 0; i < response.data.length; ++i) {
var iKEY = srt === 'dish' || srt === 'semidish' ? response.data[i]["iDISH_KEY"] : response.data[i]["iMERC_KEY"];
var item =
{
iDISH_KEY: response.data[i]["iDISH_KEY"],
iMERC_KEY: response.data[i]["iMERC_KEY"],
iKEY: iKEY,
cDICA_NME: response.data[i]["cDICA_NME"],
cDICA_UNI: response.data[i]["cDICA_UNI"],
cSEARCH_RESULT: response.data[i]["cDICA_NME"] + " ID: " + iKEY
}
$scope.SearchResults.push(item);
}
$(objTrigger).autocomplete({
source: $scope.SearchResults,
select: function (event, ui) {
$(objTrigger).val(ui.item.cSEARCH_RESULT);
$(objTrigger).parent().parent().find("#inputDish_ID").val(ui.item.iKEY);
$(objTrigger).parent().parent().find("inputDish_UNI").val(ui.item.cDICA_UNI);
}
});
}, function failure() {
alert("Napaka pri iskanju!");
})
}
}
On the server side I've included:
ScriptBundle scriptsControllerDefinition = new ScriptBundle("~/scripts/ControllerDefinition");
scriptsControllerDefinition.Include("~/static/scripts/jquery-1.11.0.min.js");
scriptsControllerDefinition.Include("~/static/jquery.ui/js/jquery-ui-1.10.4.custom.js");
scriptsControllerDefinition.Include("~/Scripts/angular.js");
scriptsControllerDefinition.Include("~/Scripts/Angular/CalendarDefinition/calendarDefinitionModule.js");
scriptsControllerDefinition.Include("~/Scripts/Angular/CalendarDefinition/calendarDefinitionController.js");
And here is .cshtml:
<div class="form-group col-sm-12">
<label for="addDish" class="col-sm-2 control-label" style="padding-left:0;">Dodaj jed: </label>
<div class="col-sm-10">
<table id="tblDishes" style="width:100%;border-collapse:collapse;">
<tbody>
<tr id="1">
<td>
<div class="col-sm-2" style="padding-left:0;padding-right:0;">
<input id="inputDish_ID" type="text" class="form-control" placeholder="ID" readonly />
</div>
<div class="col-sm-7" style="padding-right:0;">
<input id="inputDish_NME" type="text" class="form-control" placeholder="Vnesite jed" ng-keyup="SearchDishSemiDishMerc('dish');" />
</div>
<div class="col-sm-1" style="padding-right:0;">
<input id="inputDish_UNI" type="text" class="form-control" placeholder="Enota" readonly />
</div>
<div class="col-sm-1" style="padding-right:0;">
<input id="inputDish_QUA" type="text" class="form-control bfh-number" placeholder="Količina" />
</div>
<div class="col-sm-1" style="padding-right:0;">
<span class="glyphicon glyphicon-plus add-new-dish pull-left" style="font-size:18px;color:green;cursor:pointer;padding-top:1px;"></span>
<span class='glyphicon glyphicon-trash delete-dish pull-right' style='font-size:18px;color:red;cursor:pointer;padding-top:1px;'></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div><br />

AngularJS: Validators in Controller no binding with HTML side

All in-line validations in HTML side are working OK, but when I use functions in my Controller (functions ingresarNuevoEmpleador and limpiarNuevoEmpleador), always get $invalid=true. $setPristine neither works.
Apparently both sides are referencing different objects because controller functions
do not modify the state of the html side validators.
<form name="frmEmpleadorDirecto" novalidate>
<div class="row">
<div class="col-xs-8 col-sm-8">
<div class="form-group has-feedback"
ng-class="{'has-error': frmEmpleadorDirecto.nempleador.$invalid && (frmEmpleadorDirecto.nempleador.$touched || frmEmpleadorDirecto.$submitted)}">
<label for="input501">Empleador Directo</label>
<input type="text" class="form-control text-uppercase" name="nempleador" placeholder="Nombre Empleador" ng-model="objEmpleador_.nombreEmpleador_" ng-minlength="2" ng-maxlength="30" ng-required="true">
<span class="help-block" ng-if="frmEmpleadorDirecto.nempleador.$error.minlength && frmEmpleadorDirecto.nempleador.$touched">too short</span>
<span class="help-block" ng-if="frmEmpleadorDirecto.nempleador.$error.maxlength && frmEmpleadorDirecto.nempleador.$touched">too long</span>
<span class="help-block" ng-if="frmEmpleadorDirecto.nempleador.$error.required && frmEmpleadorDirecto.nempleador.$touched">required</span>
</div>
</div>
</div>
<div class="text-right">
<button type="submit" class="btn btn-success btn-mm" ng-disabled="frmEmpleadorDirecto.$pristine || frmEmpleadorDirecto.$invalid" ng-click="ingresarNuevoEmpleador()">Aceptar</button>
<button type="button" class="btn btn-warning btn-mm" ng-click="limpiarNuevoEmpleador()">Limpiar</button>
</div>
</form>
Controller:
angular.module('BlurAdmin.pages.empleador_')
.controller('CtrlEmpleadorNuevo',CtrlEmpleadorNuevo);
function CtrlEmpleadorNuevo($scope,$http,$rootScope) {
$scope.objEmpleador_ = new eva.Empleador_();
$scope.ingresarNuevoEmpleador = function()
{
console.log("Nombre: " + $scope.objEmpleador_.nombreEmpleador_); //OK
if($scope.objEmpleador_.$valid) //always invalid
{
console.log('valid!');
}else {
console.log('invalid!'); }
}
$scope.limpiarNuevoEmpleador = function ()
{
$scope.objEmpleador_.$setPristine; //no changes
$scope.objEmpleador_.nombreEmpleador_ = ''; //Works: reset html field
}
}
Objects:
eva.Empleador_ = function() {
var self = this;
self.nombreEmpleador_ = '';
};
Your form is bound on your $scope and inputs and their validity can be reached following the name attribute.
$scope.ingresarNuevoEmpleador = function(){
console.log("Nombre: " + $scope.objEmpleador_.nombreEmpleador_); //OK
if($scope.frmEmpleadorDirecto.nempleador.$valid) {
console.log('valid!');
}else {
console.log('invalid!');
}
};
Plunker

angularjs - [$injector:modulerr] error

<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Batch editable table</title>
<link rel='stylesheet prefetch' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'>
<link rel='stylesheet prefetch' href='https://cdn.rawgit.com/esvit/ng-table/v0.8.1/dist/ng-table.min.css'>
<link rel='stylesheet prefetch' href='css/nqjzro.css'>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div ng-app="myApp" class="container-fluid">
<div class="row">
<div class="col-xs-12">
<h2 class="page-header">Batch editable table</h2>
<div class="row">
<div class="col-md-6">
<div class="bs-callout bs-callout-info">
<h4>Overview</h4>
<p>Example of how to create a batch editable table.</p>
</div>
</div>
<div class="col-md-6">
<div class="bs-callout bs-callout-warning">
<h4>Notice</h4>
<p>There are several directives in use that track dirty state and validity of the table rows. Whilst they are reasonally capable they are <em>not production tested - use at your own risk!</em> More details...</p>
<div ng-show="isExplanationOpen">
<p>If you look at the declarative markup for the <code>ngTable</code> you'll see a bunch of nested <code>ngForm</code> directives, with a common ancestor <code>ngForm</code> at the level of the table element. Each nested <code>ngForm</code> propogates their <code>$dirty</code> and <code>$invalid</code> state to this top level <code>ngForm</code>. This works great as you can enable/disable the buttons for saving the table based on the status of this single top-level <code>ngForm</code>.</p>
<p>This works up till the point that the user select's a new page to display in the table. At which point the existing nested <code>ngForm</code> directives are swapped out for new instances as the new data page is loaded. These new <code>ngForm</code> directives are always pristine and valid and this status propogates setting the corrosponding state on the top-level to be pristine and valid even though rows from the previous page are dirty and possibly invalid.</p>
<p>The solution is to have a set of directives that sit parallel to the <code>ngForm</code> directives that remember the state of the rows when the corrosponding <code>ngFrom</code> directives are destroyed and recreated. When <code>ngForm</code> directives are recreated they have their status reset by the directives that have remembered this state.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" ng-controller="demoController as demo">
<h3>ngTable directive</h3>
<div class="brn-group pull-right">
<button class="btn btn-default" ng-if="demo.isEditing" ng-click="demo.cancelChanges()">
<span class="glyphicon glyphicon-remove"></span>
</button>
<button class="btn btn-primary" ng-if="!demo.isEditing" ng-click="demo.isEditing = true">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button class="btn btn-primary" ng-if="demo.isEditing" ng-disabled="!demo.hasChanges() || demo.tableTracker.$invalid" ng-click="demo.saveChanges()">
<span class="glyphicon glyphicon-ok"></span>
</button>
<button class="btn btn-default" ng-click="demo.add()">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<table ng-table="demo.tableParams" class="table table-bordered table-hover table-condensed editable-table" ng-form="demo.tableForm" disable-filter="demo.isAdding" demo-tracked-table="demo.tableTracker">
<colgroup>
<col width="70%" />
<col width="12%" />
<col width="13%" />
<col width="5%" />
</colgroup>
<tr ng-repeat="row in $data" ng-form="rowForm" demo-tracked-table-row="row">
<td title="'Name'" filter="{name: 'text'}" sortable="'name'" ng-switch="demo.isEditing" ng-class="name.$dirty ? 'bg-warning' : ''" ng-form="name" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.name}}</span>
<div class="controls" ng-class="name.$invalid && name.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="text" name="name" ng-model="row.name" class="editable-input form-control input-sm" required />
</div>
</td>
<td title="'Age'" filter="{age: 'number'}" sortable="'age'" ng-switch="demo.isEditing" ng-class="age.$dirty ? 'bg-warning' : ''" ng-form="age" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.age}}</span>
<div class="controls" ng-class="age.$invalid && age.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="number" name="age" ng-model="row.age" class="editable-input form-control input-sm" required/>
</div>
</td>
<td title="'Money'" filter="{money: 'number'}" sortable="'money'" ng-switch="demo.isEditing" ng-class="money.$dirty ? 'bg-warning' : ''" ng-form="money" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.money}}</span>
<div class="controls" ng-class="money.$invalid && money.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="number" name="money" ng-model="row.money" class="editable-input form-control input-sm" required/>
</div>
</td>
<td>
<button class="btn btn-danger btn-sm" ng-click="demo.del(row)" ng-disabled="!demo.isEditing"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
</table>
</div>
<div class="col-md-6" ng-controller="dynamicDemoController as demo">
<h3>ngTableDynamic directive</h3>
<div class="brn-group pull-right">
<button class="btn btn-default" ng-if="demo.isEditing" ng-click="demo.cancelChanges()">
<span class="glyphicon glyphicon-remove"></span>
</button>
<button class="btn btn-primary" ng-if="!demo.isEditing" ng-click="demo.isEditing = true">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button class="btn btn-primary" ng-if="demo.isEditing" ng-disabled="!demo.hasChanges() || demo.tableTracker.$invalid" ng-click="demo.saveChanges()">
<span class="glyphicon glyphicon-ok"></span>
</button>
<button class="btn btn-default" ng-click="demo.add()">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<table ng-table-dynamic="demo.tableParams with demo.cols" class="table table-bordered table-condensed table-hover editable-table" ng-form="demo.tableForm" disable-filter="demo.isAdding" demo-tracked-table="demo.tableTracker">
<colgroup>
<col width="70%" />
<col width="12%" />
<col width="13%" />
<col width="5%" />
</colgroup>
<tr ng-repeat="row in $data" ng-form="rowForm" demo-tracked-table-row="row">
<td ng-repeat="col in $columns" ng-class="rowForm[col.field].$dirty ? 'bg-warning' : ''" ng-form="{{col.field}}" demo-tracked-table-cell>
<span ng-if="col.dataType !== 'command' && !demo.isEditing" class="editable-text">{{row[col.field]}}</span>
<div ng-if="col.dataType !== 'command' && demo.isEditing" class="controls" ng-class="rowForm[col.field].$invalid && rowForm[col.field].$dirty ? 'has-error' : ''" ng-switch="col.dataType">
<input ng-switch-default type="text" name="{{col.field}}" ng-model="row[col.field]" class="editable-input form-control input-sm" required />
<input ng-switch-when="number" type="number" name="{{col.field}}" ng-model="row[col.field]" class="editable-input form-control input-sm" required />
</div>
<button ng-if="col.dataType === 'command'" class="btn btn-danger btn-sm" ng-click="demo.del(row)" ng-disabled="!demo.isEditing"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
</table>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.min.js'></script>
<script src='https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.js'></script>
<script src="js/index.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular-route.js"></script>
</body>
</html>
The above is html code
angular.module("myApp", ["ngTable", "ngTableDemos"]);
(function() {
"use strict";
angular.module("myApp").controller("demoController", demoController);
demoController.$inject = ["NgTableParams", "ngTableSimpleList"];
function demoController(NgTableParams, simpleList) {
var self = this;
var originalData = angular.copy(simpleList);
self.tableParams = new NgTableParams({}, {
dataset: angular.copy(simpleList)
});
self.deleteCount = 0;
self.add = add;
self.cancelChanges = cancelChanges;
self.del = del;
self.hasChanges = hasChanges;
self.saveChanges = saveChanges;
//////////
function add() {
self.isEditing = true;
self.isAdding = true;
self.tableParams.settings().dataset.unshift({
name: "",
age: null,
money: null
});
// we need to ensure the user sees the new row we've just added.
// it seems a poor but reliable choice to remove sorting and move them to the first page
// where we know that our new item was added to
self.tableParams.sorting({});
self.tableParams.page(1);
self.tableParams.reload();
}
function cancelChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
self.tableParams.settings({
dataset: angular.copy(originalData)
});
// keep the user on the current page when we can
if (!self.isAdding) {
self.tableParams.page(currentPage);
}
}
function del(row) {
_.remove(self.tableParams.settings().dataset, function(item) {
return row === item;
});
self.deleteCount++;
self.tableTracker.untrack(row);
self.tableParams.reload().then(function(data) {
if (data.length === 0 && self.tableParams.total() > 0) {
self.tableParams.page(self.tableParams.page() - 1);
self.tableParams.reload();
}
});
}
function hasChanges() {
return self.tableForm.$dirty || self.deleteCount > 0
}
function resetTableStatus() {
self.isEditing = false;
self.isAdding = false;
self.deleteCount = 0;
self.tableTracker.reset();
self.tableForm.$setPristine();
}
function saveChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
originalData = angular.copy(self.tableParams.settings().dataset);
}
}
})();
(function() {
"use strict";
angular.module("myApp").controller("dynamicDemoController", dynamicDemoController);
dynamicDemoController.$inject = ["NgTableParams", "ngTableSimpleList"];
function dynamicDemoController(NgTableParams, simpleList) {
var self = this;
var originalData = angular.copy(simpleList);
self.cols = [{
field: "name",
title: "Name",
filter: {
name: "text"
},
sortable: "name",
dataType: "text"
}, {
field: "age",
title: "Age",
filter: {
age: "number"
},
sortable: "age",
dataType: "number"
}, {
field: "money",
title: "Money",
filter: {
money: "number"
},
sortable: "money",
dataType: "number"
}, {
field: "action",
title: "",
dataType: "command"
}];
self.tableParams = new NgTableParams({}, {
dataset: angular.copy(simpleList)
});
self.deleteCount = 0;
self.add = add;
self.cancelChanges = cancelChanges;
self.del = del;
self.hasChanges = hasChanges;
self.saveChanges = saveChanges;
//////////
function add() {
self.isEditing = true;
self.isAdding = true;
self.tableParams.settings().dataset.unshift({
name: "",
age: null,
money: null
});
// we need to ensure the user sees the new row we've just added.
// it seems a poor but reliable choice to remove sorting and move them to the first page
// where we know that our new item was added to
self.tableParams.sorting({});
self.tableParams.page(1);
self.tableParams.reload();
}
function cancelChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
self.tableParams.settings({
dataset: angular.copy(originalData)
});
// keep the user on the current page when we can
if (!self.isAdding) {
self.tableParams.page(currentPage);
}
}
function del(row) {
_.remove(self.tableParams.settings().dataset, function(item) {
return row === item;
});
self.deleteCount++;
self.tableTracker.untrack(row);
self.tableParams.reload().then(function(data) {
if (data.length === 0 && self.tableParams.total() > 0) {
self.tableParams.page(self.tableParams.page() - 1);
self.tableParams.reload();
}
});
}
function hasChanges() {
return self.tableForm.$dirty || self.deleteCount > 0
}
function resetTableStatus() {
self.isEditing = false;
self.isAdding = false;
self.deleteCount = 0;
self.tableTracker.reset();
self.tableForm.$setPristine();
}
function saveChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
originalData = angular.copy(self.tableParams.settings().dataset);
}
}
})();
(function() {
"use strict";
angular.module("myApp").run(configureDefaults);
configureDefaults.$inject = ["ngTableDefaults"];
function configureDefaults(ngTableDefaults) {
ngTableDefaults.params.count = 5;
ngTableDefaults.settings.counts = [];
}
})();
/**********
The following directives are necessary in order to track dirty state and validity of the rows
in the table as the user pages within the grid
------------------------
*/
(function() {
angular.module("myApp").directive("demoTrackedTable", demoTrackedTable);
demoTrackedTable.$inject = [];
function demoTrackedTable() {
return {
restrict: "A",
priority: -1,
require: "ngForm",
controller: demoTrackedTableController
};
}
demoTrackedTableController.$inject = ["$scope", "$parse", "$attrs", "$element"];
function demoTrackedTableController($scope, $parse, $attrs, $element) {
var self = this;
var tableForm = $element.controller("form");
var dirtyCellsByRow = [];
var invalidCellsByRow = [];
init();
////////
function init() {
var setter = $parse($attrs.demoTrackedTable).assign;
setter($scope, self);
$scope.$on("$destroy", function() {
setter(null);
});
self.reset = reset;
self.isCellDirty = isCellDirty;
self.setCellDirty = setCellDirty;
self.setCellInvalid = setCellInvalid;
self.untrack = untrack;
}
function getCellsForRow(row, cellsByRow) {
return _.find(cellsByRow, function(entry) {
return entry.row === row;
})
}
function isCellDirty(row, cell) {
var rowCells = getCellsForRow(row, dirtyCellsByRow);
return rowCells && rowCells.cells.indexOf(cell) !== -1;
}
function reset() {
dirtyCellsByRow = [];
invalidCellsByRow = [];
setInvalid(false);
}
function setCellDirty(row, cell, isDirty) {
setCellStatus(row, cell, isDirty, dirtyCellsByRow);
}
function setCellInvalid(row, cell, isInvalid) {
setCellStatus(row, cell, isInvalid, invalidCellsByRow);
setInvalid(invalidCellsByRow.length > 0);
}
function setCellStatus(row, cell, value, cellsByRow) {
var rowCells = getCellsForRow(row, cellsByRow);
if (!rowCells && !value) {
return;
}
if (value) {
if (!rowCells) {
rowCells = {
row: row,
cells: []
};
cellsByRow.push(rowCells);
}
if (rowCells.cells.indexOf(cell) === -1) {
rowCells.cells.push(cell);
}
} else {
_.remove(rowCells.cells, function(item) {
return cell === item;
});
if (rowCells.cells.length === 0) {
_.remove(cellsByRow, function(item) {
return rowCells === item;
});
}
}
}
function setInvalid(isInvalid) {
self.$invalid = isInvalid;
self.$valid = !isInvalid;
}
function untrack(row) {
_.remove(invalidCellsByRow, function(item) {
return item.row === row;
});
_.remove(dirtyCellsByRow, function(item) {
return item.row === row;
});
setInvalid(invalidCellsByRow.length > 0);
}
}
})();
(function() {
angular.module("myApp").directive("demoTrackedTableRow", demoTrackedTableRow);
demoTrackedTableRow.$inject = [];
function demoTrackedTableRow() {
return {
restrict: "A",
priority: -1,
require: ["^demoTrackedTable", "ngForm"],
controller: demoTrackedTableRowController
};
}
demoTrackedTableRowController.$inject = ["$attrs", "$element", "$parse", "$scope"];
function demoTrackedTableRowController($attrs, $element, $parse, $scope) {
var self = this;
var row = $parse($attrs.demoTrackedTableRow)($scope);
var rowFormCtrl = $element.controller("form");
var trackedTableCtrl = $element.controller("demoTrackedTable");
self.isCellDirty = isCellDirty;
self.setCellDirty = setCellDirty;
self.setCellInvalid = setCellInvalid;
function isCellDirty(cell) {
return trackedTableCtrl.isCellDirty(row, cell);
}
function setCellDirty(cell, isDirty) {
trackedTableCtrl.setCellDirty(row, cell, isDirty)
}
function setCellInvalid(cell, isInvalid) {
trackedTableCtrl.setCellInvalid(row, cell, isInvalid)
}
}
})();
(function() {
angular.module("myApp").directive("demoTrackedTableCell", demoTrackedTableCell);
demoTrackedTableCell.$inject = [];
function demoTrackedTableCell() {
return {
restrict: "A",
priority: -1,
scope: true,
require: ["^demoTrackedTableRow", "ngForm"],
controller: demoTrackedTableCellController
};
}
demoTrackedTableCellController.$inject = ["$attrs", "$element", "$scope"];
function demoTrackedTableCellController($attrs, $element, $scope) {
var self = this;
var cellFormCtrl = $element.controller("form");
var cellName = cellFormCtrl.$name;
var trackedTableRowCtrl = $element.controller("demoTrackedTableRow");
if (trackedTableRowCtrl.isCellDirty(cellName)) {
cellFormCtrl.$setDirty();
} else {
cellFormCtrl.$setPristine();
}
// note: we don't have to force setting validaty as angular will run validations
// when we page back to a row that contains invalid data
$scope.$watch(function() {
return cellFormCtrl.$dirty;
}, function(newValue, oldValue) {
if (newValue === oldValue) return;
trackedTableRowCtrl.setCellDirty(cellName, newValue);
});
$scope.$watch(function() {
return cellFormCtrl.$invalid;
}, function(newValue, oldValue) {
if (newValue === oldValue) return;
trackedTableRowCtrl.setCellInvalid(cellName, newValue);
});
}
})();
This is javascript file
The above code is angularjs. It displays table loading data with add row, delete, edit.
Please solve this. Am getting error [$injector:modulerr] . Please help me to solve
Edit: They created different codepen for ngTableDemos look here
To run your sample you need to load that ngTableDemos related code first then your sample.
For codepen, to understand what are the files they are using to run any sample check Pen Setting JavaScript tab carefully.
Probably you didn't load "ngTableDemos" module, so if it is needed load associate file or remove it like
angular.module("myApp", ["ngTable"]);

Update css settings with an object received

I am trying to modify my css with settings which I received from an object.
I send the object after the user select the options from a form.
Now I want to use this to change my layout, but I don't know exactly how.
My template looks like this
div class="btn btn-primary" ng-click="showMenu()">Layout Settings</div>
<div ng-show="themeSelected">
<form>
<div class="row">
<div>
<div class="form-group">
<label>Background color for views</label>
<input type="text" name="background_color" id="background_color" ng-model="selectedLayout.background_color" class="form-control" />
</div>
<div class="form-group">
<label>Background image</label>
<input type="file" name="background_image" id="background_image" ng-model="selectedLayout.background_image" class="form-control" style="width:25%" />
</div>
<div class="form-group">
<label>Buttons color</label>
<input type="text" name="buttons_color" id="buttons_color" ng-model="selectedLayout.buttons_color" class="form-control" />
</div>
<div class="form-group">
<label>Buttons size</label>
<input type="text" name="buttons_size" id="buttons_size" ng-model="selectedLayout.buttons_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Buttons font color</label>
<input type="text" name="buttons_font_color" id="buttons_font_color" ng-model="selectedLayout.buttons_font_color" class="form-control" />
</div>
<div class="form-group">
<label>Headers size</label>
<input type="text" name="headers_size" id="headers_size" ng-model="selectedLayout.headers_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Headers color</label>
<input type="text" name="headers_color" id="headers_color" ng-model="selectedLayout.headers_color" class="form-control" />
</div>
<div class="form-group">
<label>Info size</label>
<input type="text" name="info_size" id="info_size" ng-model="selectedLayout.info_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Info font color</label>
<input type="text" name="info_font_color" id="info_font_color" ng-model="selectedLayout.info_font_color" class="form-control" />
</div>
</div>
</div>
</form>
<button class="btn btn-primary" ng-click="saveChanges(selectedLayout)">Save</button>
<button class="btn btn-primary" ng-click="cancel()">Cancel</button>
<div style="color: red" ng-show="errors.length > 0">{{errors}}</div>
</div>
And when I press Save button all those defined above are in an object. Now I want to use those settings to actually change my layout.
This is my controller where i defined the saveChanges
'use strict';
(function () {
angular.module('routerApp').controller('LayoutController', function ($scope,layoutRepository) {
$scope.showMenu = function() {
$scope.themeSelected = true;
};
$scope.cancel = function() {
$scope.themeSelected = false;
};
$scope.saveChanges = function (selectedLayout) {
layoutRepository.saveLayoutInfo(selectedLayout);
$scope.themeSelected = false;
};
$scope.selectedLayout = {};
window.model = $scope.selectedLayout;
});
}());
This is the layoutRepository
'use strict';
(function () {
angular.module('routerApp').factory('layoutRepository', function ($http) {
return {
saveLayoutInfo: function (selectedLayout) {
console.log(selectedLayout);
$http({
method: "POST",
url: "/api/LayoutSettings",
data: selectedLayout,
cache: false
});
}
};
});
}());
You can use this. It will take your data, retrieve the classnames, keys and values from it and appends it to the correct element:
var data = data.split("\n"); //split the received data on a new line
for (var i = 0; i < data.length; i++)
{
var className = data[i].substr(0, data[i].indexOf("_")); //classname = part before the "_"
var csskey = data[i].substr(data[i].indexOf("_")+1, data[i].indexOf(":");
var cssvalue = data[i].substr(data[i].indexOf(":")+1).trim().replace("\"",""); strip whitespaces and quotations
loadCSSIntoControl(className, {key:csskey, value : cssvalue });
}
function loadCSSIntoControl(classname, css)
{
if (css.key == "size")
{
css.key = "font-size";
}
//iterate over all elements using Array.prototype.map
Array.prototype.map.call(document.querySelectorAll("."+classname), function(elem) {
elem.style[css.key.replace("_", "-")] = css.value; //replace underscore with dash
});
}
Note: if the first part isn't a class name, you can easily change this to another type of selector.
Bind the settings to a scope (are they an object/json? Your output seems odd)
<button data-ng-style="{
background: selectedLayout.buttons_color,
color: selectedLayout.buttons_font_color,
fontSize: selectedLayout.buttons_size
}">Button</button>
This is assuming the data looks like this:
selectedLayout = {
buttons_color: "rgb(83, 255, 0)",
buttons_font_color: "rgb(255, 247, 0)",
buttons_size: "11px",
headers_color: "rgb(187, 52, 202)",
headers_size: "18px",
info_font_color: "rgb(17, 15, 15)",
info_size: "12px"
}

No call function of parent in Reactjs

I have two function in Reactjs. When function one call a function of function two. There have error same as
"Uncaught TypeError: this.props.onButonShowClick is not a function"
This is function one :
var HiddenEdit = React.createClass({
_handleOnClick: function(e) {
e.preventDefault(),
this.props.onButonShowClick(true);
},
render: function() {
return (<span className="col-lg-2 btn-action-group">
<a className="add btn-for-view" href={this.props.url_detail} id="btn-add-chapter-123" title="Add"></a>
<a className="edit btn-for-view" onClick={this._handleOnClick} id={this.props.id_chapter} title="Edit"></a>
<a className="trash btn-for-delete btn-delete-episode" data-confirm="Are you sure?" rel="nofollow" data-method="delete" href=""></a>
</span>);
}
});
And this is a function two
var ChapterList = React.createClass({
_handleOnPaginate: function(pageNumber) {
this.props.inPagenate(pageNumber)
},
getInitialState: function () {
return {
childVisible: false
};
},
_handleOnClick: function(params) {
this.state.childVisible = params;
},
render: function() {
var showEdit = this.state.childVisible;
var chapterNodes = this.props.data.chapters.map(function(chapter, index) {
var url_chapter_detail = "/admin/chapters/" + chapter.chapter_id + "/chapter_details";
var btn_edit = "btn-edit-chapter-" + chapter.chapter_id;
var href_delete = "/admin/mangas/" + chapter.manga_id + "/chapters/" + chapter.chapter_id;
var div_chapter = "chapter-" + chapter.chapter_id;
return (<div className="row item-data" id={div_chapter}>
<div className="text-data-row">
<input value={chapter.chapter_id} type="hidden" className="chapter[manga_id]" id="chapter_manga_id" />
<span className="col-lg-1">
<input className="form-control" disabled="disabled" type="text" value={chapter.chapter_order} name="chapter[chapter_order]" id="chapter_chapter_order" />
</span>
<span className="col-lg-5">
<input className="form-control" disabled="disabled" type="text" value={chapter.chapter_name} name="chapter[chapter_name]" id="chapter_chapter_name" />
</span>
<span className="col-lg-2">
<input className="form-control" disabled="disabled" type="text" value={chapter.by_group} name="chapter[by_group]" id="chapter_by_group" />
</span>
{
showEdit ? <ShowEdit url_detail={url_chapter_detail} id_chapter="btn_edit" /> : <HiddenEdit onButonShowClick={this._handleOnClick} url_detail={url_chapter_detail} id_chapter="btn_edit" />
}
</div>
</div>);
});
return (<div className="form-post-movie" id="form-post-movie" role="form">
<div className="col-lg-12">
<div className="list-data">
{chapterNodes}
</div>
</div>
</div>
<div className="div-page">
<PaginatorSection totalPages={this.props.data.meta.total_pages} currentPage={this.props.data.meta.current_page} onPaginate={this._handleOnPaginate} />
</div>
</div>);
}
});
Can anyone help me solve this?
Well, this is undefined inside the callback of an array map. (Array.prototype.map() docs)
And so will be the value passed as onButtonShowClick prop.
<HiddenEdit onButonShowClick={this._handleOnClick} url_detail={url_chapter_detail} id_chapter="btn_edit" />
You should fix it by passing this as the second parameter of that map:
var chapterNodes = this.props.data.chapters.map(function(chapter, index) { /*...*/ }, this);
Also, you should take a look at React's docs about dynamic children.

Categories