Dynamically adding angularjs directive with a $http to get - javascript

I am actually stuck with an interesting problem,
I am trying to make soemthing of this sort:
input key 1 , input value 1
input key 2 , input value 2 < button to add more >
< submit button >
Basically a user can click submit and issue a Get request to a given URL. now when he click to add more a new row appears with two input fields, where he can add more http get paarmeters.
I tried coding this up, but I am close to this: http://jsfiddle.net/d2jL2n35/1/
Could you please help me...
Two questions:
How to dynamically add a new row after the plus box is clicked?
myApp.directive('options',function(){
return {
restrict:"E",
template:"<div><input placeholder='params1' type='text'/><input placeholder='params2' type='text'><button><i class='glyphicon glyphicon-plus'></i></button></div>"
}
})
Ok solved the first one by using $compile: http://jsfiddle.net/KyEr3/216/
How to get all the params and issue a get request?????

Here is a very rough example:
http://jsfiddle.net/d2jL2n35/9/
The crux of it is you have to store each set of values in an array, and reuse your directive to show them. I removed your http call because I didn't want to sketch out the echo service. But if you had a real service it could be like this:
$http.get('/options').success( function( result ) {
$scope.options = result;
} );

I'm guessing that you want something like this:
Example
View:
<div ng-app="myApp" ng-controller="mainController">
<options parameters="parameters"></options>
</div>
Controller:
var myApp = angular.module('myApp',[])
.factory('yourAPI', ['$http', function ($http) {
var submitResults = function (parameters) {
return $http.get("http://wwww.whateverURL.com?" + parameters.map(function(parameter){return parameter.key + "=" + encodeURI(parameter.val) }).join('&'));
};
return {
submitResults: submitResults
}
}])
.directive('options', function(){
return{
restrict:"E",
replace:true,
template:
"<div><option parameter='parameter' ng-repeat='parameter in parameters'></option>"+
"<div>"+
"<input type='text' placeholder='key' ng-model='newKey' /> " +
"<input type='text' placeholder='value' ng-model='newVal' /> " +
"<button ng-click='addItem()'><i class='glyphicon glyphicon-plus'></i></button>" +
"</div>" +
"<input type='submit' value='submit' ng-click='sendRequest()' /></div>",
scope: { parameters:'='},
controller: function($scope, yourAPI){
$scope.newKey="";
$scope.newVal="";
$scope.addItem = function(){
$scope.parameters.push({key:$scope.newKey, val:$scope.newVal});
$scope.newKey="";
$scope.newVal="";
};
$scope.sendRequest = function(){
yourAPI.submitResults($scope.parameters).success(function(data, status, headers) {
console.log(data);
});
}
}
}
})
.directive('option', function(){
return {
restrict:'E',
require: '^options',
replace: true,
scope: { parameter:'='},
template: "<div>"+
"<input type='text' placeholder='key' ng-model='parameter.key' />" +
"<input type='text' placeholder='value' ng-model='parameter.val' /></div>"
}
})
.controller('mainController', function($scope){
$scope.parameters=[];
});
Notice that jsFiddle will block the get request, but this should work in your app.

It looks like you're ready to upgrade to LEVEL 2 AWESOME ANGULAR HACKER!
Since your directives are so small, it might be easier as a beginner to only have one directive, instead of two. Directives are really great tools, but can make things more complex.
To get the data out of the inputs, you can use ng-model (https://docs.angularjs.org/api/ng/directive/ngModel)
So after copy-pasting your options' template into your values template, you can put a click event, that is ng-click=addParam() on the button.
HTML:
<button ng-click="addParam()>
JS:
$scope.param1 = null;
$scope.param2 = null;
$scope.addParam = function () {
$http.get('some url', {param1: param1, param2: param2}).success(data) {
// add another option row
};
}
In this function, you're going to want to add another option row. One way to do this is have a for loop that creates a div for each ng-repeat, so you're template will look like this:
<div ng-repeat="n in noptions">
<input placeholder="params1" ng-model="param1" />
<button ng-click="addParam()>
</div>
To add another option row, you can then add 1 to noptions, like $noptions +=1
https://docs.angularjs.org/api/ng/directive/ngRepeat
$scope.noptions = 0;
$http.get('some url', {param1: param1, param2: param2}).success(data) {
$scope.noptions +=1;
};
and another option row will be dynamically added.

Related

Add new HTML content with different values in Angularjs

I created a directive to add some content whenever the button "add" is clicked. But I don't know how to get all values in these new inputs.
HTML Code
angular.module('myApp', [])
.controller('myController', function() {
})
.directive('addContent', function($document, $compile) {
return {
restrict: 'A',
replace: false,
link: function(scope, element, attr) {
element.on('click', function() {
var newcontent = '<input type="text" ng-model="myModel"><br>';
angular.element($document[0].querySelector('.newcontent')).append($compile(newcontent)(scope));
})
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="newcontent" ng-app="myApp" ng-controller="myController">
<button type="button" add-content>Add</button><br><br>
</div>
So, how can I set a different ng-model value to each one new input that is created and, how can I get this values in my controller?
You could go with something like this:
The Idea:
A base name can be defined from the html where the directive is being applied.
An incremental number is used in the directive when creating new inputs (the view controller (programmer) where this model is used must be aware of that). Actually, you could use any other strategy you'd prefer better in this case. I've used this one for simplicity and stating my point.
The code (see below snippet):
In the directive
Create a counter for incrementing as new inputs are added: var count = 0;
Take the base name specified in the html with var model = scope.$eval(attr['addContent']);
Modify the newcontent variable to use that base name and the incremental counter like this: var newcontent = '<input type="text" ng-model="' + model + (count++) + '"><br>';
The controller
For organization, create a variable for holding the base name: $scope.buttonModel = 'buttonModelReference';
Access the value of those new models like this: $scope[$scope.buttonModel + $scope.index] where $scope.index is the index of the input (where 0 is the first input created)
The view
Use the modified directive like this add-content="buttonModel" where buttonModel is the variable defined in the controller.
Plus code (for demonstration purposes only)
The showModel function shows the value of one (dynamic created) input passing as reference the index of the input (0 zero is the index of the first input created)
The Snippet
angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.index;
$scope.buttonModel = 'buttonModelReference';
$scope.showModel = function() {
console.log($scope[$scope.buttonModel + $scope.index]);
}
})
.directive('addContent', function($document, $compile) {
var count = 0;
return {
restrict: 'A',
replace: false,
link: function(scope, element, attr) {
element.on('click', function() {
var model = scope.$eval(attr['addContent']);
var newcontent = '<input type="text" ng-model="' + model + (count++) + '"><br>';
angular.element($document[0].querySelector('.newcontent')).append($compile(newcontent)(scope));
})
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="newcontent" ng-app="myApp" ng-controller="myController">
<button type="button" ng-click="showModel()">showModel</button> <input ng-model="index" type="number" placeholder="select the model index starting from 0" /> <br><br>
<button type="button" add-content="buttonModel">Add</button><br><br>
</div>

Why can`t I access scope via controller?

I am working on passion project. And I cant access scope to pass data to back-end frame work.
Here is my index file
<div id="main-menu" ng-controller="appCtrl">
//some other code
<div id="includedDocumentsFilter" style="float:right; display:none; padding-right: 10px;">
<my-documents validate-options="validateDialogOptions()" call-dialog="showDialog()"> </my-documents>
</div>
//some other code
</div>
My custom directive
'use strict';
dbApp
.directive('myDocuments', [
function () {
var documentTemplate =
' <div class="caption-row">' +
'<kendo-button style="width:62px" ng-click="changeDocument(true)"> Ok </kendo-button>'+
'<kendo-button style="width:62px" ng-click="changeDocument(false)" > Revert changes </kendo-button>'+
'</div>'
}
return {
scope: true,
template: documentTemplate
}
}]
)
My controller
$scope.changeDocument = function (applyFilter) {
if (applyFilter === true) {
//Here is where I cant access $scope
}
}
Firstly, I see a extra closing curly braces in your directive. Secondly in your html code there is display:none in div with id "includedDocumentsFilter". Just wondering if you are hiding the div, how will you be able to see the template defined in your directive. I have added a working jsfiddle link below using your above mentioned code
dbApp.directive('myDocuments', [
function () {
var documentTemplate =
' <div class="caption-row">' +
'<kendo-button style="width:62px" ng-click="changeDocument(true)"> Ok </kendo-button>'+
'<kendo-button style="width:62px" ng-click="changeDocument(false)" > Revert changes </kendo-button>'+
'</div>'
return {
scope: true,
template: documentTemplate
}
}]
)
JsFiddle link: https://jsfiddle.net/anilsarkar/gk2dfh1p/21/
Note: I have replaced kendo-button with span in jsfiddle

how to add two values in angular js data commng from get request

unable to add {{ cost -- selling_price }} please suggest any one how to add two numbers when whole data comes from get or post request (work on ajax data two add two numbers )
<script type="text/javascript">
var app = angular.module('associate', []);
app.controller('addassociate', ['$scope', '$http', function($scope,$http) {
$http.get('<?php echo base_url();?>index.php/user/addassociate_request')
.then(function (response) {
$scope.data1 = response.data;
angular.forEach($scope.data1, function (value, key) {
for (x in value) {
$('#planoutlook').append('<tr><td>' + value[x].plan_type + '</td><td>' + value[x].plan_name + '</td><td> <input class="form-control" ng-model="cost" value="' + value[x].cost + '"></td><td> <input class="form-control" ng-model="cost" value="' + value[x].selling_price + '"></td><td><div class="form-group discount-form-group"><input class="form-control" ng-model="discount" name="plan[]" data-id="' + value[x].id + '" value="' + value[x].default_discount_percentage + '"></div></td><td>{{cost -- selling_price}}</td></tr>');
}
});
})
}]);
</script>
The angular approach avoids appending elements to the DOM.
You need an ng-repeat binded to an array. When you receive data from your async request you must add that data to your previously binded array. So ng-repeat can update the DOM for you and you will avoid binding problems
You cannot dynamically add an element using jQuery and expect that some angular inside would magically work. To create such HTML with angular dynamically, you need to compile the template (see $compile).
Now, for you problem, the logic itself is flawed. What you should do is using ng-show and ng-repeat. The idea is:
define a $scope.data1
in your view, use ng-show="data1" on your table to hide it when no data is available
use ng-repeat="data in data1" to iterate in your data and create your rows
upon receiving data, assign them to $scope.data1
Here is an example of HTML with ng-show and ng-repeat to create a table:
<div ng-controller="MyCtrl">
<table ng-show="data1">
<tr ng-repeat="data in data1">
<td>{{data.one}}</td>
<td>{{data.two}}</td>
<td>{{data.one - data.two}}</td>
</tr>
</table>
</div>
In your callback, use:
$scope.data1 = data;
$scope.$apply(); // if the callback was not triggered by angular
This fiddle gives you an example: https://jsfiddle.net/qdtakovu/

Why is my directive updating as a result of changes in another instance of the same directive?

I created a simple directive wrapper around the HTML file input to make angular binding work. Here's my directive:
angular.module('myApp').directive('inputFile', InputFileDirective);
function InputFileDirective() {
var bindings = {
selectLabel: '#',
};
return {
restrict: 'E',
require: ['inputFile', 'ngModel'],
scope: true,
controllerAs: 'inputFileCtrl',
bindToController: bindings,
controller: function () {
},
template: `<input class="ng-hide" id="input-file-id" type="file" />
<label for="input-file-id" class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}</label>`,
link: link
};
function link(scope, element, attrs, controllers) {
if (angular.isDefined(attrs.multiple)) {
element.find('input').attr('multiple', 'multiple');
}
var inputFileCtrl = controllers[0];
var ngModelCtrl = controllers[1];
inputFileCtrl.getButtonLabel = function () {
if (ngModelCtrl.$viewValue == undefined || ngModelCtrl.$viewValue.length == 0) {
return inputFileCtrl.selectLabel;
}
else {
return ngModelCtrl.$viewValue.length + (ngModelCtrl.$viewValue.length == 1 ? " file" : " files") + " selected";
}
};
element.on('change', function (evt) {
ngModelCtrl.$setViewValue(element.find('input')[0].files);
ngModelCtrl.$render();
});
}
};
And here's the HTML
<body ng-app="myApp" ng-controller="MyController as ctrl">
<form name="ctrl.myForm">
<input-file select-label="Select Attachment" ng-model="ctrl.attachment1"></input-file>
<input-file select-label="Select Attachment" ng-model="ctrl.attachment2"></input-file>
</form>
</body>
It's pretty simple and it works - if only one is on the page. As soon as I add a second one, I notice that only the first one ever updates. If I select a file with the second one, the label updates on the first one. My suspicions are that the require ['inputFile'] is pulling in the controller for the first directive instance into the link function or something (which shouldn't happen). Even now as I type this, that doesn't really make sense to me. So what's going on here and how do I fix it?
Here's a codepen for you guys to play with and try to figure it out: http://codepen.io/astynax777/pen/PzzBRv
Your problem is not with your angular... is with you html.
You are assigning the same id twice.
Change your template to this:
template: `<label class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}<input class="ng-hide" type="file" /></label>`

Populate ng model from value

I am trying to populate the ng-model from a value, but don't want it to update until it is saved. To do this I have the following code;
Controller;
var SettingsController = function (roleService) {
var ctrl = this;
ctrl.rename = function(name) {
ctrl.account.name = name;
};
roleService.role.settings().then(function (result) {
ctrl.account = result.data.account;
}, function (result) {
console.log(result);
});
};
A simple controller, it gets the current settings from a service and sets it to the ctrl.
When the rename(name) is called I update the name of the account (for now it just updates the scope but soon it will update also the back-end)
To rename your account I have the following piece of code
<input type="text" data-ng-model="account.name" />
<button type="button" data-ng-click="ctrl.rename(account.name)">
Rename
</button>
I use controler as so ctrl == SettingsController
Now I use data-ng-model="account.name" to update the name. This is done so I only update the name when the button is called. The only issue is how do I get the ctrl.account.name value to the input, without bubbling it up.
I could add $scope to my controller with $scope.account but that seems overkill to me. Isn't there a way to copy/populate a ng-model from an other value or some kind?
To get to the controller I use the angular routerProvider;
$routeProvider
.when('/settings/', {
templateUrl: '/user/template/settings/',
controller: 'SettingsController',
controllerAs: 'ctrl'
});

Categories

Resources