How can I set Attributes to dynamically added buttons? I've tried but if I change attr all button types also bind together. I want to set {type:Submit} to first added button, {type:Reset} to second button, and {type:Cancel} to third button. How can I set different attr values to 3 different buttons?
Working DEMO
var app = angular.module('myapp', ['ngSanitize']);
app.controller('AddCtrl', function($scope, $compile) {
$scope.add_Button = function(index) {
var buttonhtml = '<div ng-click="selectButton()"><button id="button_Type">Button</button>//click//</div>';
var button = $compile(buttonhtml)($scope);
angular.element(document.getElementById('add')).append(button);
$scope.changeTosubmit = function () {
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "submit");
compile(el);
}
};
$scope.changeToreset = function () {
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "reset");
compile(el);
}
};
$scope.changeTocancel = function () {
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "cancel");
compile(el);
}
};
};
$scope.selectButton = function () {
$scope.showButton_Types = true;
};
});
function compile(element) {
var el = angular.element(element);
$scope = el.scope();
$injector = el.injector();
$injector.invoke(function ($compile) {
$compile(el)($scope);
});
};
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.5.0-rc.0/angular-sanitize.min.js"></script>
</head>
<body ng-controller="AddCtrl">
<button ng-click="add_Button($index)">Add Buttons</button>
<hr>
<div id="add"></div>
<form ng-show="showButton_Types">
<div>
<label>change button types(?)</label><br/>
<input ng-click="changeTosubmit()" name="submit" type="radio"> Submit
<input ng-click="changeToreset()" name="submit" type="radio"> Reset
<input ng-click="changeTocancel()" name="submit" type="radio"> Cancel
</div>
</form>
</body>
</html>
I did quite research on this and here is the solution I came up with. I think this would be useful and perfectly match into your case. Instead if else you should have try AngularJs directives as below. For references visit
https://github.com/yearofmoo/angular-forms-refactor
and to understand how directive and its scope works here is perfect explanation with example visit
https://docs.angularjs.org/guide/compiler
angular.module('FieldEditor', [])
.controller("FieldEditorPageController",
function() {
var self = this;
this.fields = [{
type: 'submit'
}];
this.inputTypes = [{
value: "reset",
title: "button[reset]"
}, {
value: "cancel",
title: "button[cancel]"
}, {
value: "submit",
title: "button[submit]"
}];
this.newField = function() {
self.fields.push({
type: 'submit'
});
};
this.removeField = function(field) {
var index = self.fields.indexOf(field);
if (index >= 0) {
self.fields.splice(index, 1);
}
};
})
.controller("appButtonController", ['$scope', '$attrs',
function($scope, $attrs) {
var self = this;
var directiveScope = $scope.$parent;
this.options = directiveScope.$eval($attrs.model);
this.onOk = function() {
alert(self.options.type + ' button clicked');
}
}
])
.directive('appButton', function($compile) {
return {
transclude: true,
template: '<button ng-click="buttonCtrl.onOk()" type="">{{type|uppercase}}</button>',
scope: {
title: '#',
type: '#'
},
restrict: 'E',
replace: true,
controller: 'appButtonController',
controllerAs: 'buttonCtrl',
}
})
angular.module("MyApp", ['FieldEditor']);
<!doctype html>
<html>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="js/controller.js"></script>
<head>
<meta charset="utf-8" />
<title>
Dynamic Fields and Directive Binding
</title>
</head>
<body>
<div ng-app="MyApp">
<h1>Dynamic Fields and Directive Binding</h1>
<div ng-controller="FieldEditorPageController as pageCtrl">
<div>
<div ng-repeat="field in pageCtrl.fields track by $index">
<div>
<div>
{{ $index + 1 }}.
</div>
<div>
<div>
<label>Button Type:</label>
<select ng-model="field.type" ng-options="entry.value as entry.title for entry in pageCtrl.inputTypes" name="field_type" required>
</select>
<app-button type="{{field.type}}" text="button" model="field">
</app-button>
</div>
<div>
Remove
</div>
</div>
</div>
</div>
<div>
<span>
<a href="" ng-click="pageCtrl.newField()">
Add Button
</a>
</span>
</div>
</div>
</div>
</div>
</body>
</html>
Part of your problem is that you are creating elements that all have the same id.
From MDN:
The Element.id property represents the element's identifier, reflecting the id global attribute.
It must be unique in a document, and is often used to retrieve the element using getElementById. Other common usages of id include using the element's ID as a selector when styling the document with CSS.
-- Mozilla Developer Network -- Web API -- Element.id
So in your code create html with unique id attributes.
var buttonId = 0;
function buttonhtml() {
buttonId++;
return '<div ng-click="selectButton(' +buttonId+ ')">' +
'<button id="button-' +buttonId+ '">' +
'Button #' +buttonId+
'</button></div>';
};
var button = $compile(buttonhtml())($scope);
By doing this you will be creating conformant HTML and you will be able to change specific button attributes using getElementById.
Related
I have a drop-down inside ng-repeat and a add button that can add new drop-down to the list as I've shown in the JSFiddle, and I want to restrict the second drop-down to select the first selected value in the second drop-down. So the value selected in the first drop-down should not allowed to select in the second or hide that value.
In my old question pankaj parkar given the answer,But I am unable to integrate that answer in my JSFiddle.
ng-repeat="post in posts | filter: { type: selectedValue }"
Please help me on this.
This is my old question
My JSFiddle.
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.names = ['Mobile','Office','Home'];
$scope.choices = [{id: 'choice1'}];
$scope.addNewChoice = function() {
var newItemNo = $scope.choices.length+1;
$scope.choices.push({'id':'choice'+newItemNo});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="angularjs-starter" ng-controller="MainCtrl">
<fieldset ng-model='y' ng-repeat="choice in choices">
<select>
<option ng-model='x1' ng-repeat = "x in names">{{x}}</option>
</select>
</fieldset>
<button class="addfields" ng-click="addNewChoice()">Add fields</button>
</div>
Put your options in scope items array. Get your output result from choices array.
var app = angular.module('angularjs-starter', []);
app.filter("itemFilter", function(){
return function(items, choice){
filtered_items=[];
for(var i=0;i<items.length;i++){
if(items[i].choiceID==null || items[i].TYPE_ID==choice.TYPE_ID)
filtered_items.push(items[i]);
}
return filtered_items;
}
});
app.controller('MainCtrl', function($scope) {
$scope.items = [
{"TYPE_ID":1,"TYPE_NAME":"Jpeg"},
{"TYPE_ID":2,"TYPE_NAME":"Odt"},
{"TYPE_ID":3,"TYPE_NAME":"docx"},
{"TYPE_ID":4,"TYPE_NAME":"xls"}
];
$scope.choices = [];
$scope.addNewChoice = function() {
var newChoiceID = 'choice'+$scope.choices.length+1;
for(var i=0;i<$scope.items.length;i++){
if($scope.items[i].choiceID==null){
$scope.items[i].choiceID = newChoiceID;
$scope.choices.push({'id':newChoiceID,TYPE_ID:$scope.items[i].TYPE_ID});
break;
}
}
};
$scope.updateValue = function(choice) {
for(var i=0;i<$scope.items.length;i++){
if($scope.items[i].choiceID==choice.id)
$scope.items[i].choiceID = null;
if($scope.items[i].TYPE_ID==choice.TYPE_ID)
$scope.items[i].choiceID = choice.id;
}
};
$scope.addNewChoice();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
<div ng-app="angularjs-starter" ng-controller="MainCtrl">
<fieldset ng-repeat="choice in choices">
<select ng-model="choice.TYPE_ID" ng-change="updateValue(choice)">
<option ng-repeat = "item in items | itemFilter:choice" value="{{item.TYPE_ID}}">{{item.TYPE_NAME}}</option>
</select>
</fieldset>
<button class="addfields" ng-show="items.length>choices.length" ng-click="addNewChoice()">Add fields</button>
<h4>Data for backend</h4>
<ul>
<li ng-repeat="choice in choices">TYPE_ID: {{choice.TYPE_ID}}</li>
</ul>
</div>
You can try this solution, which works based on the first options selected value, based on the requirement you can change it.
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.names = ['Mobile','Office','Home'];
$scope.selectedValue = [];
$scope.choices = [{id: 'choice1', options: $scope.names}];
$scope.addNewChoice = function() {
var newItemNo = $scope.choices.length+1;
// First Frame options list
var ele = document.getElementById('myOptions');
var angularEle = angular.element( ele );
var value = angularEle[0].value;
$scope.selectedValue = $scope.names.filter(item => item !== value)
$scope.choices.push({'id':'choice'+newItemNo, options: $scope.selectedValue});
};
});
.addfields {
-webkit-appearance: button;
cursor: pointer;
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.min.js"></script>
<div id='mainC' ng-app="angularjs-starter" ng-controller="MainCtrl">
<fieldset ng-model='y' ng-repeat="choise in choices">
<p> <ul>Id, Options
<li ng-repeat="(k,v) in choise">{{v}}</li>
</ul></p>
<select id='myOptions'>
<option ng-model='x1' ng-repeat = "x in choise.options">{{x}}</option>
</select>
</fieldset>
<button class="addfields" ng-click="addNewChoice()">Add fields</button>
</div>
Is this possible in angularjs/jquery/javascript?
<div ng-init="font='h2'">
<h1> h1 is this size </h1>
<{{font}}> this is a {{font}}</{{font}}>
</div>
How to dynamically change html tags?
ps: I already tried this code, but with no success.
Here's a plain Javascript solution:
var i=0;
setInterval(function()
{
document.getElementById("changeable").outerHTML = "<h" + (i+1) + " id=\"changeable\">" + document.getElementById("changeable").innerHTML + "</h" + (i+1) + ">";
i++;
if(i>=5){
i=0;
}
},1000);
<div>
<h1> h1 is this size </h1>
<h2 id="changeable"> this is a header tag</h2>
</div>
Certainly possible with both JavaScript and JQuery.
JavaScript: use document.getElementById("MyId").outerHTML
JQuery: See this for reference - http://api.jquery.com/insertAfter/#selector
This may seem like a bad practice to modify DOM elements through JavaScript (although possible)
If using Angular, I would recommend using ng-if or a combination of ng-if and ng-include if you would want to conditionally load up a new view/html
As far as jQuery you could use the replaceWith() method. You'd just need to preserve the text/class during the click event.
$(function() {
$('.button').on('click', function() {
var $span = $('.span');
var lvl = $(this).data('lvl');
$span.replaceWith(`<${lvl} class="span">${$span.text()} as an ${lvl}<${lvl}>`);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="button" data-lvl="h2">Change to h2</button>
<button class="button" data-lvl="h5">Change to h5</button>
<div ng-init="font='h2'">
<h1>h1 is this size </h1>
<span class="span">this is a font</span>
</div>
You can do this with a custom directive:
var app = angular.module('app', []);
app.controller('MyController', ['$scope', '$timeout', function($scope, $timeout) {
$scope.font = 'h2';
$timeout(function() {
$scope.font = 'h3';
$timeout(function() {
$scope.font = 'h4';
$timeout(function() {
$scope.font = 'h5';
}, 1000);
}, 1000);
}, 1000);
}]);
app.directive('font', function($interpolate, $compile) {
return {
restrict: 'E',
scope: false,
link: function($scope, $element, $attr) {
var content = $element.html();
$scope.$watch('font', function(newVal) {
$element.contents().remove();
var tag = $interpolate('<{{font}}>{{content}}</{{font}}>')
({
font: $scope.font,
content: content
});
var e = angular.element(tag);
$element.append($compile(e)($scope));
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-init="font='h2'" ng-app="app" ng-controller="MyController">
<h1> h1 is this size </h1>
<font>This is a {{font}}</font>
</div>
I have this code:
app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function() {
var vm = this;
vm.unit = '';
vm.unitForm = "unitForm";
vm.unitInput = "unitInput";
vm.amount = '';
vm.amountForm = "amountForm";
vm.amountInput = "amountInput";
vm.errorText = "Error";
vm.pattern = new RegExp("^[0-9]*$");
vm.calculate = calculate;
function calculate(first, second){
var firstFloat = parseFloat(first.replace(",","."));
var secondFloat = parseFloat(second.replace(",","."));
var total = (firstFloat * secondFloat).toFixed(2);
console.log('calculating', firstFloat, secondFloat, total)
return total.toString().replace(".",",");
}
});
app.directive('textInput', function textInput() {
return {
restrict: 'E',
templateUrl: 'text-input.html',
scope: {
myClass: "#",
value: '=?value',
formName: '=',
inputName: '=',
pattern: '=',
errorText: '=',
change: "&"
}
};
});
text-input.html
<form name="formName">
<input type="text"
name="inputName"
ng-model="value"
ng-class="myClass"
ng-pattern="pattern"
ng-trim="false"
ng-change="change()"
/>
<div data-ng-show="formName.inputName.$error.pattern">
{{errorText}}
</div>
</form>
index.html
<text-input my-class="input"
form-name="vm.unitForm"
input-name="vm.unitInput"
pattern="vm.pattern"
error-text="vm.errorText"
value="vm.unit"
change="vm.total = vm.calculate(vm.amount, vm.unit)"
></text-input>
<br>
<text-input my-class="input"
form-name="vm.amountForm"
input-name="vm.amountInput"
pattern="vm.pattern"
error-text="vm.errorText"
value="vm.amount"
change="vm.total = vm.calculate(vm.amount, vm.unit)"
></text-input>
vm.unit: {{vm.unit}}
<br>
vm.amount: {{vm.amount}}
<br><br>
Just jusing *:{{vm.unit*vm.amount}}
<br>
Change:
{{vm.total}}
Link to plnkr: http://plnkr.co/edit/DOc0v7o7arS6PhYOHaK0?p=preview
As can be seen, I have a directive that binds a variable to a function.
For some reason I can't figure out, the whole thing lags.
To see what's wrong do this: Enter a value in the top box, i.e 2. Enter a value in the second box, i.e 3.
The models lag in input. To see a change from the function, you need to enter another value. But the function now uses the values before your last input!
So, I am thoroughly confused here. What's going on and why won't this work?
UPDATE
I thought about this and this is what I'm thinking. Maybe I can just filter the list on input (when I type into the input box) rather than automatically have this filter. Is this possible?
I've created a combo box with angular, and I've bound a scope variable to my input using ng-model. Right now the functionality is, you can search for an item in the dropdown. when you click on an item in the dropdown, that value is copied into the input.
however, when I go back into the input to search again, it only brings up items that match the search, which is expected. But I'd like to make it so when you click on the input again, the text that was in the input stays there, but the drop down shows all results.
is this doable? Maybe I can bind a different scope variable to the value of the input?
heres the fiddle: https://jsfiddle.net/mLsbmfb7/25/
html:
<div class='center' ng-app="myapp" ng-controller="appCont">
<div class='form-box'>
<div class='inputs-box'>
<div>
<span>First</span>
<input type='text' ng-model="firstname"/>
</div>
<div>
<span>Last</span>
<input type='text' ng-model="lastname"/>
</div>
</div>
<div class='add-button' ng-click="addPerson()">
add
</div>
</div>
<div class='ppl-list-title'>
<div class='inputs-box'>
<div class='inline-block-top find-word'>Find</div>
<div class='inline-block-top'>
<input id='filter-input' type='text' ng-model='filterText'/>
<div>
<ul class='hidden'>
<li ng-repeat='person in people2 | filter:{fullName:filterText}'
ng-click='setInputValue(person.fullName)'>
<span class=''>{{person.fullName}}</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
controller and jquery:
var myapp = angular.module("myapp", []);
myapp.controller('appCont', function($scope) {
$scope.firstname = "";
$scope.lastname = "";
$scope.fullname = function() {
return $scope.firstname + ' ' + $scope.lastname;
};
var Person = function(){
this.firstname = "";
this.lastname = "";
this.isActive = true;
this.fullName = "";
};
function getFullName(first, last) {
return first
+ " "
+ last
};
function getPerson(first, last, active) {
var newPerson = new Person();
newPerson.firstname = first;
newPerson.lastname = last;
newPerson.isActive = active;
newPerson.fullName = first + ' ' + last;
return newPerson;
};
$scope.addPerson = function() {
var personToAdd =
getPerson($scope.firstname, $scope.lastname, true);
$scope.people2.push(personToAdd);
$scope.firstname = '';
$scope.lastname = '';
};
$scope.setInputValue = function(full) {
$scope.filterText = full;
};
$scope.people2 = [
getPerson("first", "test", true),
getPerson("second", "try", false),
getPerson("third", "testing", true)];
});
$(document).ready(function() {
$('#filter-input').on('focusin', function() {
$('ul').slideToggle();
});
$('#filter-input').on('focusout', function() {
$('ul').slideToggle();
});
});
function stringFullTrim(word) {
while(word.indexOf(' ') > -1) {
word = word.replace(' ', ' ');
}
return word.trim();
}
Did it by using a fake text input to update the real filter.
<input id='filter-input' type='text' ng-model='temp' ng-keyup='filterText = temp'/>
<input id='filter-input' type='hidden' ng-model='filterText'/>
Then on selecting, copy text into it and wipe the filter, so next search would be fresh again.
<li ng-repeat='person in people2 | filter:{fullName:filterText}'
ng-click='setInputValue(person.fullName); $parent.temp = person.fullName; $parent.filterText = ""'>
You might want to handle some edge cases like user typed the full thing but didn't select.
Note: the $parent is used because of ng-repeat is creating a child scope. The usual way to solve this is to use "the dot" but sometimes I feel like using $parent.
I've edited your fiddle
I'm struggling with angularjs directive templates. The {{variable}} works in a very strange way inside a ng-repeat,
<div ng-controller="MyCtrl">
<h2>here i am</h2>
<button type="button" ng-click="addItem()" class="btn btn-primary">Howdy</button>
<div ng-repeat="item in items track by $index" itemlist></div>
</div>
<script type="text/ng-template" id="template.html">
<div>
Howdy {{item.itemNum}} {{item.name}}
</div>
</script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.count = 0;
$scope.items = [];
var newItem = {
itemNum: 0,
name: "New"
};
$scope.addItem = function () {
newItem.itemNum = $scope.count;
console.log('adding item ' + newItem.itemNum);
$scope.items.push(newItem);
$scope.count += 1;
};
});
myApp.directive('itemlist', function ($compile) {
return {
templateUrl: 'template.html',
};
});
I have created a jsfiddle showing my problem here: http://jsfiddle.net/dk253/8jm5tjvf/23/.
What am I missing or doing wrong?
Thanks!
The reason is you are updating the property on the same object reference (newItem) every time. So it updates all other items in the array because they all just point to the same object or in other words they are all same. You could instead get the copy of the object using angular.copy and push that item.
var item = {
itemNum: 0,
name: "New"
};
$scope.addItem = function () {
var newItem = angular.copy(item); //Get the copy
newItem.itemNum = $scope.count;
Fiddle