I'm working on an AngularJS project that uses an API to deal with data. Now I'm implementing the 'create' functionality using $resource. Everything was going well except the naming conversion: I use camelCase but the API accepts snake_case only.
Is there a way to automatically convert these keys to snake_case?
Service:
services.factory('Salons', ['$resource',
function ($resource) {
return $resource('/salons/:slug', {
slug: "#slug"
});
}
]);
Controller:
controllers.controller('CreateSalonController', ['$scope', 'Salons',
function ($scope, Salons) {
$scope.submit = function() {
Salons.save(this.salon);
};
}
]);
View:
<form name="salonForm" role="form" ng-submit="submit()">
<div class="form-group">
<label for="salonContactFirstName">First name</label>
<input name="contactFirstName" type="text" class="form-control" id="salonContactFirstName" data-ng-model="salon.contactFirstName" />
</div>
...
I have not found any built-in solution so I implemented one:
A new service:
services.factory('Util', function () {
var Util = {
stringToSnakeCase: function (input) {
return input.replace(/([0-9A-Z])/g, function ($1) {
return "_" + $1.toLowerCase();
});
},
objectKeysToSnakeCase: function (input) {
var output = {};
_.each(input, function (val, key) {
output[Util.stringToSnakeCase(key)]
= _.isObject(val) ? Util.objectToSnakeCase(val) : val;
});
return output;
}
};
return Util;
}
);
And the updated controller:
controllers.controller('CreateSalonController', ['$scope', 'Salons', 'Util',
function ($scope, Salons, Util) {
$scope.submit = function() {
Salons.save(Util.objectKeysToSnakeCase(this.salon));
};
}
]);
Related
I am trying to create a react component with imported data from Google API. I can see the code is working in the console.log but when I try to use that code in React render method, I am not getting anything. When I move my function inside the class it comes up as the function not defined. I cannot understand why?
function handleTouchTap() {
console.log('CHIP selected');
authorize();
}
function handleAccounts(response) {
console.log(response.result.username);
var username = response.result.username
console.log(username);
}
function authorize(event) {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, function (response) {
gapi.client.load('analytics', 'v3').then(function () {
console.log(response);
gapi.client.analytics.management.accounts.list().then(handleAccounts);
});
});
}
class Chips extends React.Component {
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={handleTouchTap}
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.username}
</Chip>
</div>
);
}
}
In most cases, when you want to render something that might change, you want to add it to the state. That way when you call setState the component knows it needs to rerender and show the changes.
Here I added the functions as component methods, so that you can call this.setState on the result. Ideally you would probably do this with redux and use actions but this will work as a self contained component.
class Chips extends React.Component {
handleTouchTap = () => {
console.log('CHIP selected');
this.authorize();
}
handleAccounts = (response) => {
var username = response.result.username;
this.setState({
username
});
}
authorize = (event) => {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, (response) => {
gapi.client.load('analytics', 'v3').then(() => {
console.log(response);
gapi.client.analytics.management.accounts.list()
.then(this.handleAccounts);
});
});
}
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={this.handleTouchTap}
style={styles.chip}>
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.state.username}
</Chip>
</div>
);
}
}
This is my HTML form
<form ng-submit='create()'>
..
.
.
<input type='file' ng-model='logo' accept="image/*">
</form>
this is my controller :
$scope.create = function () {
$scope.Ent = {}
$scope.Ent.logo = $scope.logo;
ng-model won't work in input type 'file. use a custom directive to bind it
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = loadEvent.target.result;
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}]);
assign scope variable to fileread attribute
<form ng-submit='create()'>
..
.
.
<input type='file' fileread='logo' accept="image/*">
</form>
` ~ ! # # $ % ^ & * ( ) _ + = { } | [ ] \ : ' ; " < > ? , . /
I want to restrict the above mentioned special characters and numbers in the input text field. I used the
ng-pattern="/^[a-zA-Z ]*$/"
to restrict the special characters. This pattern is blocking all the special characters. I am facing issue when I want to enter name "PĂ©rez Gil" I don't want to restrict other language text.
Updates:
I think $parsers is the best options here. See the updated code and plunker.
Controller
angular.module('ngPatternExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.regex = /^[^`~!##$%\^&*()_+={}|[\]\\:';"<>?,./1-9]*$/;
}])
.directive('myDirective', function() {
function link(scope, elem, attrs, ngModel) {
ngModel.$parsers.push(function(viewValue) {
var reg = /^[^`~!##$%\^&*()_+={}|[\]\\:';"<>?,./1-9]*$/;
// if view values matches regexp, update model value
if (viewValue.match(reg)) {
return viewValue;
}
// keep the model value as it is
var transformedValue = ngModel.$modelValue;
ngModel.$setViewValue(transformedValue);
ngModel.$render();
return transformedValue;
});
}
return {
restrict: 'A',
require: 'ngModel',
link: link
};
});
Template
<input type="text" ng-model="model" id="input" name="input" my-directive />
Here's a updated example on Plunker
https://plnkr.co/edit/eEOJLi?p=preview
Old Answers:
Since you already have a list of characters that you want to restrict, you can spell them out in the ng-pattern expression like:
Controller
angular.module('ngPatternExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.regex = /^[^`~!##$%\^&*()_+={}|[\]\\:';"<>?,./1-9]*$/;
}]);
Template
<input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" />
Here's a working example on Plunker
https://plnkr.co/edit/eEOJLi?p=preview
Use Directives to restrict Special characters:
angular.module('scPatternExample', [])
.controller('scController', ['$scope', function($scope) {
}])
.directive('restrictSpecialCharactersDirective', function() {
function link(scope, elem, attrs, ngModel) {
ngModel.$parsers.push(function(viewValue) {
var reg = /^[a-zA-Z0-9]*$/;
if (viewValue.match(reg)) {
return viewValue;
}
var transformedValue = ngModel.$modelValue;
ngModel.$setViewValue(transformedValue);
ngModel.$render();
return transformedValue;
});
}
return {
restrict: 'A',
require: 'ngModel',
link: link
};
});
In Html:
<input type="text" ng-model="coupon.code" restrict-Special-Characters-Directive>
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<input type="text" ng-change="Check(myValue)" ng-model="myValue" />
<p ng-show="test">The Special Character not accept.</p>
</div>
<script>
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope,ngModel) {
$scope.Check= function(x) {
var reg = /^[^`~!##$%\^&*()_+={}|[\]\\:';"<>?,./]*$/;
if (!x.match(reg)) {
$scope.myValue = x.substring(0, x.length-1);
$scope.test=true;
}
else
{
$scope.test=false;
}
};
}]);
</script>
</body>
</html>
This one is going to be a long one :)
So here is the idea, I wanna use same html page for two controllers , problem is , that page in insert state wont load , because of ng-repeat="employee in employee" because its non existent in insert controller.
What my repeater does it just fills textboxes , it doesnt repeat anything , its just a single form and it fills information of that one single employee , am i doing this wrong ?
employeeUpdate works like a charm , problem is in employeeInsert , is there a posibility that it can fill textboxes without ng-repeat part , because it does not work without it , but it does fill comboBox/select options without it.
.state('employeeUpdate', {
url: '/employeeUpdate?employeeCode=:param1',
templateUrl: 'pages/employeeUpdate.html',
controller: 'employeeUpdateCtrl',
resolve: {
employeeGatherAll: ['$http', function ($http) {
return $http.jsonp("webserviceSite&procedureName=wsEmployeeGatherAll 'param','param'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}],
employeeSelectByCode: ['$http','$location', function ($http, $location) {
var employeeCode = $location.search().employeeCode
return $http.jsonp("webServiceSite&procedureName=wsEmployeeSelectByCode 'paramet','parame','" + employeeCode + "'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}]
}
})
.state('employeeInsert', {
url: '/employeeInsert',
templateUrl: 'pages/employeeUpdate.html',
controller: 'employeeInsertCtrl',
resolve: {
employeeGatherAll: ['$http', function ($http) {
return $http.jsonp("webServiceSiteUrl&procedureName=wsEmployeeGatherAll 'parametar','parametar'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}],
}
})
So i have selectView as well , where i list all employees, and on click i go to employeeUpdate where i send code trough url as well , my html employeeUpdate page looks something like this :
<div ng-repeat="employee in employee">
<div class="col-md-4">
<label>Employee code</label>
<input type="text" class="form-control" id="txtEmployeeCode" ng-model='employee.employeeCode' />
</div>
<div class="col-md-4">
<label>Status</label>
<select id="Select3" class="form-control" ng-model="employee.statusCode" ng-options="item.code as item.name for item in employeeGather.status">
<option value="">Select status</option>
</select>
</div>
</div>
And these are the controllers
angular
.module('app')
.controller('employeeUpdateCtrl', ['$scope', 'employeeGatherAll', 'employeeSelectByCode', function ($scope, employeeGatherAll, employeeSelectByCode) {
$scope.employee = employeeSelectByCode.data.employee;
$scope.employeeGather = employeeGatherAll.data
}])
.controller('employeeInsertCtrl', ['$scope', 'employeeGatherAll', function ($scope, employeeGatherAll) {
$scope.employeeGather = employeeGatherAll.data
}])
employee.SelectByCode.data.employee[0] was the soulution , without ng-repeat
I have an MVC application using angularJS. I have a primary navigation and secondary navigation. I am using ngRoute for primary navigation. I made secondary navigation template a directive that I can use in all the other pages. The template used in the directive needs some input parameters.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
resolve: {
SecNavItems: ["$http", function($http){
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
return data;
});
}]
},
controller: 'AdminController'
})}]);
var AdminController = function ($scope, SecNavItems) {
$scope.secList = SecNavItems;
}
AdminController.$inject = ["$scope", "SecNavItems"];
myApp.controller("AdminController", AdminController);
Web method code:
[HttpGet]
public JsonResult SecondaryNavigation(string pageName)
{
Dictionary<string, string> secnavItems = new Dictionary<string, string>();
secnavItems.Add("1", "Item1");
secnavItems.Add("2", "Item2");
var navigationItemsJson = Json(secnavItems, JsonRequestBehavior.AllowGet);
return navigationItemsJson;
}
Page1 code is
<secondary-navigation></secondary-navigation>
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: {},
templateUrl: '/navigation/secondaryNavigation'
}
});
Partial view template:
<div style="height:100%; width:25%; background-color:#675c5c; color: white; float:left">
#foreach (KeyValuePair<int, string> navItem in secList)
{
#navItem.Value<br /><br />
}
</div>
<div style="height:100%; width:75%; float:right"></div>
When I run the application I do not see the Item1 and Item2 in the page instead I see {{object}}
Please advise what I am missing in passing the parameters to the template used in the directive.
Thank you.
Figured what went wrong.
I had to create a html template of secondary navigation. I then included the web service call in the admincontroller, set the object value to the webservice result and added it to the routeProvider. I then
set the scope to false in the directive.
Following are the changes I made.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
controller: 'AdminController'
})}]);
var AdminController = function ($scope, $http) {
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
$scope.secList = data;
});
}]
},
}
AdminController.$inject = ["$scope", "$http"];
myApp.controller("AdminController", AdminController);
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: false,
templateUrl: '/navigation/secondaryNavigation'
}
});