angularjs dynamic model in template - javascript

I need to create dynamic inputs, textareas..etc. So for each input type I have a separate template. So a text field template could look like this:
<script type="text/ng-template" id="/input.html">
<input type="text" ng-model="model" />
</script>
and what I am trying to achieve is something like this:
<div ng-include="" src="'/input.html'" ng-init="model = var1"></div>
<div ng-include="" src="'/input.html'" ng-init="model = var2"></div>
so I can create text fields with the same template and have a different model for each one. That works actually and gets the data passed, but if I type something in the text field it doesn't get applied to the scope variable.
Here's a fiddle to illustrate this: http://jsfiddle.net/uAm99/2/

You could try to implement this feature in "angular directive way". It can empower the HTML tag, such as reusable template (just mentioned in your implementation). Here is a simple example:
HTML
<body ng-app="myApp">
<div ng-controller="myCtrl">
<custom-input data="var1"></custom-input>
<custom-input data="var2"></custom-input>
{{var1}}
{{var2}}
</div>
</div>
JS
angular.module("myApp",[])
.controller("myCtrl",function($scope){
$scope.var1 = "foo";
$scope.var2 = "bar";
})
.directive("customInput",function(){
return {
restrict:'E',
scope: {
data:"="
},
template: '<input type="text" ng-model="data" />'
};
});
And this is a jsfiddle demo
Hope it helpful.

Related

Need to add multiple divs with same content inside a single div on a click against the parent div

Here is my piece of code, a function to add a meal template:
vm.addMealTemplate = function() {
$scope.mealCount++;
$compile( $(document.createElement('div')).attr("id", 'mealDiv' + $scope.mealCount).addClass("mealDiv"+$scope.mealCount).after().html(
'<select ng-options="(option.name ) for option in mealOptions" ng-model="selectedOption'+ $scope.mealCount+'" />' +
'<input type="text" placeholder="Meal timings" id="time'+ $scope.mealCount +'"/>' +
'<a id="mealCount" ng-class="mealCount" ng-click="addItemCategory()" uib-tooltip="Add category" tooltip-trigger="mouseenter" tooltip-placement="bottom"><i class="fa fa-plus"></i></a>'
).appendTo("#meals")
// $("#meals").append(newMealDiv)
)($scope);
}
On clicking calling the addItemCategory() for the specific div, I want another div to get added as a child of that div. There can be mutiple meal templates, and for each template I can call the addItemCategory mutliple times, and I want the category to be added to the same div for which the function has been called. How do I achieve this?
Currently I am using mealCount variable from scope to have the context, but once it gets increased, I have no way to access the divs added previously, to add the new element to that div. Any way using jQuery or AngularJs?
You can use ng-repeat
For example:
angular.module('app', []).
controller('ctrl', function($scope) {
$scope.meals = [];
});
.meal {
border:1px solid;
padding:10px;
margin-bottom:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="meal in meals" class="meal">
<select ng-model="meal.count">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<input type="text" placeholder="Meal timings" ng-model="meal.timing" />
<div>
<div>Categories:</div>
<div ng-repeat="cat in meal.categories track by $index">
<input type="text" ng-model="meal.categories[$index]" />
</div>
<button ng-click="meal.categories.push('')">Add Category</button>
</div>
</div>
<button ng-click="meals.push({categories:[]})">Add meal</button>
<hr />
{{meals | json}}
</div>
Note: I changed the models etc. it's just example..
Here's an example Plunker on how your problem can be solved with ng-repeat in Angular:
http://plnkr.co/edit/POt7nFc4GqFU67SWdMp7?p=preview
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://code.angularjs.org/1.5.5/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="restaurant" ng-controller="meal-controller">
<div ng-repeat="meal in meals track by $index">
<select ng-options="option.name for option in mealOptions" ng-model="meal.selectedMeal"></select>
<input type="text" placeholder="Meal timings" id="{{'time'+ $index }}" ng-model="meal.timing"/>
<a id="mealCount" ng-class="mealCount" ng-click="addItemCategory()" uib-tooltip="Add category" tooltip-trigger="mouseenter" tooltip-placement="bottom"><i class="fa fa-plus"></i></a>
</div>
<button ng-click="addMeal()">Add meal</button>
</body>
</html>
-
// Script.js
angular.module('restaurant', [])
.run( ['$rootScope', function( $rootScope ) {
}]
);
angular.module('restaurant').controller('meal-controller', [ '$scope', function( $scope ) {
$scope.meals = [];
$scope.mealOptions = [{ name: "option1"}, { name: "option2"}, { name: "option3" } ];
$scope.addMeal = function() {
$scope.meals.push({ selectedMeal: null, timing: "timing" });
}
$scope.addItemCategory = function() {
}
}]);
I am not entirely sure about how you want the logic to work, but I am sure that you can modify this example to fit your needs.
Ng-repeat works like a loop which prints the content it is wrapping until the end of the array. Ng-repeat has a lot of features like tracking elements in the array by index, this can used to (like in the example) give each input an unique id.
If you need to make some specific changes to a meal, you can pass it as an argument, for example if you want to delete a specific meal you can have a button inside the ng-repeat like this:
<button ng-click="deleteMeal(meal)">Delete Meal</button>
This means that you do not have to access the meal specifically by, for example, its id with jQuery.
I would say it is not recommended to mix angular and jQuery the way you are doing now. Try to stick with Angular and avoid jQuery. In some special cases where you need to do element specific modifications it can be achieved by using jQlite:
https://docs.angularjs.org/api/ng/function/angular.element

How to pass HTML element into angularjs code?

I want to pass the html element into angularjs code. I have some html elements like data-form-selector='#linechart_general_form' and data-url="{% url 'horizon:admin:metering:samples'%}" I want to access these Html elements in angularjs code.
My html templates, what make to change in the following code so that its elements accessible to angularjs code.
<div class="info row detail">
<div class="col-sm-9 chart_container">
<div class="chart"
data-chart-type="line_chart"
data-url="{% url 'horizon:admin:metering:samples'%}"
data-form-selector='#linechart_general_form'
data-legend-selector="#legend"
data-smoother-selector="#smoother"
data-slider-selector="#slider">
</div>
<div id="slider"></div>
<div class="col-sm-3 legend_container">
<div id="smoother" title="Smoothing"></div>
<div id="legend"></div>
</div>
</div>
</div>
--Update-- I just reread your question. To access those ATTRIBUTES (not elements, they are values of an element) you can select the object with an identifier, then manipulate it's attributes, like so (jQuery example):
$('.chart').attr('data-form-selector', 'myNewValue');
You may need to re-initialize sopmething because of the databinding but that's where I'd start.
==================================
You need to create an angular app and controller first, then use the angularjs and ng-model directive to bind the element to a method in your controller, i.e.:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName= "John";
$scope.lastName= "Doe";
});
</script>
<div ng-app="myApp" ng-controller="myCtrl">
First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{firstName + " " + lastName}}
</div>
In this case, you'd be manipulating the $scope.firstName and $scope.lastName variables in js.
Courtesy W3Schools
http://www.w3schools.com/angular/angular_intro.asp
You can do a Directive for doing that.
https://docs.angularjs.org/guide/directive

Is there an angular directive that can restrict scope for an element in the DOM

Hi I was just wondering if there is some built-in angular directive (ng-some-directive) that allows you to restrict the scope to a particular model for the desired DOM element.
I belive I have seen something similar done before, but maybe I am thinking of knockout.js
<script>
angular.module('example', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.heading = 'Some Value';
$scope.complexModel = {...}
}]);
</script>
<div ng-controller="ExampleController">
<h1>{{ heading }}</h1>
<div ng-some-directive='complexModel.to.long.really.annoying'>
<input type='text' ng-model='variable' /> // Actually coming from complexModel.to.long.really.annoying.variable
</div>
</div>
This is a drastically simplified version
Though its not meant for it
<div ng-init='sn = complexModel.to.long.really.annoying'>
<input type='text' ng-model='sn' />
</div>

Angular data - having trouble binding updated values to scope (using slider)

I'm trying to use Angular to create a tool that accepts user input from a slider tool, and automatically updates an "estimate" field whenever the values are changed. However, the data only seems to be binding on the way to the view; the user input is displayed, but doesn't seem to register in the scope.
Here's the HTML:
<h3 ng-controller="calcController" ng-model="estimate" class="floating-menu">${{estimate}}</h3>
<form ng-controller="calcController" method="post" action="/estimate">
<div class="container">
<div class="vals">${{values.insurance}}</div>
<div id="insurance-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.insurance" ng-change="changeVal()" translate="currencyFormatting"></slider>
</div>
<div class="container">
<div class="vals">${{values.lease}}</div>
<div id="lease-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.lease" translate="currencyFormatting"></slider>
</div>
</div>
</form>
Here's the Angular:
//create the module
angular.module('Breeze', ['ngRoute', 'ngResource', 'ui.slider'])
.config(function($routeProvider) {
$routeProvider
// route for the calculator page
.when('/', {
templateUrl: 'partials/calculator.html',
controller: 'calcController'
});
})
// create the controller and inject Angular's $scope
.controller('calcController', function($scope, $http) {
$scope.values = {
// Default values
insurance: 125,
lease: 125,
};
$scope.estimate = $scope.values.insurance + $scope.values.lease
}
// Formatting for scale bar
$scope.currencyFormatting = function(value) {
return value.toString() + " $";
}
})
I've tried adding a $watch and a $broadcast function but can't seem to get them working.
This is what it looked like in Angular:
$scope.$watch("values", function(newVal, oldVal, scope) {
scope.estimate = addVals();
})
$scope.changeVal = function() {
$scope.estimate = addVals();
console.log('hi')
$scope.estimate = $scope.values.insurance + $scope.values.lease
}
Ideas?
You are using two nested ng-controller="calcController"in your HTML. Hence two instanciations of the controller (two $scope) which will have their own estimate value, so when you update the inner estimate, the upper one is not aware of that.
You should remove the second ng-controller in your <form> (if the controller were different, then you would put the estimate variable in an object such as $scope.model.estimate so properties inheritance between the two controllers actually work. But in your case there is no reason to have two controllers).
Also, you should remove that ng-model="estimate" in your <h3> tag, which has no effect.
Just setting them equal in the beginning wont work. In your view, instead of having an estimate field just use this
<div ng-controller="calcController" ng-app="Breeze">
<h3 ng-model="estimate" class="floating-menu">${{values.insurance + values.lease }}</h3>
<form method="post" action="/estimate">
<div class="container">
<div class="vals">${{values.insurance}}</div>
<div id="insurance-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.insurance" ng-change="changeVal()" translate="currencyFormatting"></slider>
</div>
<div class="container">
<div class="vals">${{values.lease}}</div>
<div id="lease-slider">
<slider floor="0" ceiling="250" value="125" step="25" precision="2" ng-model="values.lease" translate="currencyFormatting"></slider>
</div>
</div>
</div>
</form>
</div>
This will keep them adding as the values change.
Another thing that would be breaking is that you have two controller calls to the same controller and no app. Need to change it as below with the new div and remove the rest of the ng-controllers.
Also, make sure that you have the ui slide javascript file included on your page.
Did you try to bind to object instead of primitive type?
$scope.values.estimate = $scope.values.insurance + $scope.values.lease
see similar question here:
Angularjs: 2 way binding not working in included template
Here is a fiddle http://jsfiddle.net/U3pVM/9330/

Output in multiple parts of the page

index.html:
<div id="section_a">
<script type="text/x-handlebars" data-template-name="index">
First value: {{input type="text" value=one}}<br>
Second value: {{input type="text" value=two}}<br>
Result: {{result}}
</script>
</div>
<div id="section_b">
<!-- Display {{result}} here aswell -->
</div>
application.js
App.IndexController = Ember.ObjectController.extend({
one: 0,
two: 0,
result: function() {
return this.get('one') + this.get('two');
}.property('one', 'two')
});
I have a section of a page where I have some Ember interactions - a user inputs some values and a calculated result is displayed.
I now want to have the calculated result displayed in another part of the page that is outside the defined template, how would I accomplish this?
You could bind that property to the application controller and then use it anywhere you want in the application. For example:
App.ApplicationController = Ember.ObjectController.extend({
needs: ['index'],
indexResult: Ember.computed.alias('controllers.index.result')
});
Now you can use it anywhere within the application you want. Just tell the outlet's controller to need the application controller, then call that property in the template. Like so:
App.FooController = Ember.ArrayController.extend({
needs: ['application'],
//...
});
In the Foo template:
{{controllers.application.indexResult}}
Or, if you are within the application scope you can just do:
{{indexResult}}
One simple and straight forward solution would be:
<script type="text/x-handlebars" data-template-name="index">
<div id="section_a">
First value: {{input type="text" value=one}}<br>
Second value: {{input type="text" value=two}}<br>
Result: {{result}}
</div>
<div id="section_b">
<!-- Display {{result}} here aswell -->
</div>
</script>
You can also set up another outlet that can be used to display the "result". You can read more about using outlets in the Ember.js Guides at http://emberjs.com/guides/routing/rendering-a-template/

Categories

Resources