I have the following AngularJS app.
From $scope.forms I create some inputs on the html part using ng-repeat.
The thing I dont understand is how to push the data from attributes: ["title", "firstname", "lastname", "address"] inputs into values: []
Can someone explain me how to push the input values into my values key?
Or maybe if there is a best solution to explain?
function sampleCtrl($scope) {
$scope.forms = [
{
title: "Something",
attributes: ["title", "firstname", "lastname", "address"],
values: [] //here i want the values from the attributes
},
{
title: "Something else",
attributes: ["title", "name", "job", "address"],
values: [] //here i want the values from the attributes
} ]; }
http://jsfiddle.net/U3pVM/18198/
See #Grundy's answer for a direct approach where you don't have to change your model.
Do allow me to suggest a different approach though (that also includes the fact that you need to use ng-model to bind the input's value): model the attribute + value combination as an actual thing. So e.g.:
$scope.forms = [
{
title: "Something",
pairs: [{label: "title", value: ""}, {label: "firstname", value: ""}]
}
];
This view model is much easier to bind to in a view:
<div ng-repeat="pair in form.pairs">
<input type="text" placeholder="{{pair.label}}" ng-model="pair.value" />
</div>
The reason I suggest this is because the $scope works best IMO if it's tailored to being bound to in views. If you need the other format (i.e. a values array) perhaps to send it off to a back end service, you'd best map the view model back to the appropriate data format. For example:
var values = $scope.forms[0].pairs.map(function(p) {
return p.value;
});
See this forked fiddle for a full example.
You should see about ng-model. as model you can use values[$index] so, in values array values in same order as in attributes.
function sampleCtrl($scope) {
$scope.forms = [
{
title: "Something",
attributes: ["title", "firstname", "lastname", "address"],
values: [] //here i want the values from the attributes
},
{
title: "Something else",
attributes: ["title", "name", "job", "address"],
values: [] //here i want the values from the attributes
}
];
}
body {
font-family: courier new;
}
h1 {
font-size: 24px;
margin: 0 0 20px;
}
h2 {
font-size: 18px;
}
.form {
margin: 0 0 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<h1>Form</h1>
<div ng-controller="sampleCtrl">
<div class="form" ng-repeat="form in forms">
<h2>{{form.title}}</h2>
<div ng-repeat="input in form.attributes">
<input type="text" ng-model="form.values[$index]" placeholder="{{input}}" />
</div>
{{form.attributes}}
{{form.values}}
</div>
</div>
</div>
I have added the changes to your fiddle:
<div ng-app>
<h1>Form</h1>
<div ng-controller="sampleCtrl">
<div class="form" ng-repeat="form in forms">
<h2>{{form.title}}</h2>
<div ng-repeat="input in form.attributes" ng-init="mod = []">
<input type="text" placeholder="{{input}}" ng-init="mod[$index] = form.values[$index]" ng-model="mod[$index]"/>
</div>
</div>
</div>
</div>
http://jsfiddle.net/U3pVM/18201/
It's simple : Here is updated fiddle
Just added an ng-model that points at the exact same index in attributes array and that of in values array.
<div ng-app>
<h1>Form</h1>
<div ng-controller="sampleCtrl">
<div class="form" ng-repeat="form in forms">
<h2>{{form.title}}</h2>
<div ng-repeat="input in form.attributes">
<input type="text" ng-model="form.values[$index]" placeholder="{{input}}" />
</div>
</div>
<button ng-click="haha()">Test!</button>
</div>
</div>
And no change in JS. Only added new function haha() to test it out
function sampleCtrl($scope) {
$scope.forms = [
{
title: "Something",
attributes: ["title", "firstname", "lastname", "address"],
values: [] //here i want the values from the attributes
},
{
title: "Something else",
attributes: ["title", "name", "job", "address"],
values: [] //here i want the values from the attributes
}
];
$scope.haha = function(){
console.log($scope.forms);
}
}
Related
i have a problem. Right now I have a normal Kendo-Ui Multiselect which doesn´t work.
You can choose those values: 1
The problem is the following. When you select one or more values, the name of the selected values wouldn´t shown in the input field. There is only an empty box. 2
Here is one part of my code:
<div class="col-md-3">
<fieldset>
<div class="form-group">
<label class="control-label">Assigned Attributes</label>
<div class="demo-section k-content">
<select id="dropdownAttributes"></select>
</div>
</div>
</fieldset>
</div>
And the other one:
var days = [
{ text: "First", value: "1" },
{ text: "Second", value: "2" },
{ text: "Third", value: "3" },
{ text: "Fourth", value: "4" },
{ text: "Fifth", value: "5" }
];
$("#dropdownAttributes").kendoMultiSelect({
dataTextField: "text",
dataValueField: "value",
dataSource: days,
height: 200,
filter: "contains"
});
Can somebody help me with this problem?
I'm making a table that has to be dynamic, they are passing me data like this
[
{
"store_name": "daniel",
"store_id": "054050",
"store_address": "av las americas",
"store_logo": "https://centroamerica-resources.s3.amazonaws.com/walmart/express.png",
"occupancy": {
"recluta": 400,
"occupancy": 0,
"percentage": 0
},
"alerts": {
"conglomerations": 0,
"occupancy": 0
},
"visits": 0
},
{
"store_name": "expreso polar",
"store_id": "re485754re",
"store_address": "boulevard california",
"store_logo": "https://centroamerica-resources.s3.amazonaws.com/walmart/express.png",
"occupancy": {
"recluta": 300,
"occupancy": 0,
"percentage": 0
},
"alerts": {
"conglomerations": 0,
"occupancy": 0
},
"visits": 3836
},
]
This is an example of the data that they have given me in a .txt what I need is to show all this data in a table, I have created one with false data but what I need is to make it dynamic that it alone adds more data without need to create more components
for the moment, each data only has to be shown in div
<div class="">
<div class="flex">
<div class="">Name</div>
<div class="">Id</div>
<div class="">Adress</div>
<div class="">Logo</div>
<div class="">Rcluta</div>
<div class="">Ocupancy</div>
<div class="">Percentage</div>
</div>
<div class="flex">
<div class="">{store_name}</div>
<div class="">{store_id}</div>
<div class="">{store_address}</div>
<div class="">{store_logo}</div>
<div class="">{recluta}</div>
<div class="">{occupancy}</div>
<div class="">{percentage}</div>
</div>
</div>
The best practice is that feed data something like this
[
{
data: [
{ name: 'Store Name', value: 'expreso polar'},
{ name: 'Store Id', value: 're485754re'}
]
}
]
name be the label and value be the data needs to shown in the table for corresponding label
This is something very common that I come across while coding and here is what I do.
Im not sure how you are getting your json, whether it be by a fetch or if its hard coded but store it as a json object inside a variable
const [metadata, setMetadata] = useState([])
const data = response.json()
setMetadata(data);
const Table = useMemo(() => metadata.map(
({name, id, tags, address, logo}) => (
<div>
<div>Name: {name}</div>
<div>Id: {id}</div>
<div>Tags: {tags}</div>
<div>Address: {address}</div>
<div>: {logo}</div>
</div>
)
),
[metadata]);
Once you get your metadata in some sort of json format you can simply use the map function to map it all into jsx. Then call it by using <Table/>.
Using useMemo is always a good idea because it will update whenever one of the dependencies changes, in this case metadata.
In my application i have select that i bind with options and the user selected saved data on page load.
Fiddle Link for issue
<div ng-app ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="Answers['{{question.Name}}']" ng-options="option for option in question.Options">
</select>
<select ng-model="OptSelected" ng-options="option for option in question.Options">
</li>
</ul>
</div>
And in my angular controller
function QuestionController($scope) {
$scope.Answers = {};
$scope.Questions = [{ "Text": "Gender?", "Name": "GenderQuestion",
"Options": [{1,"Male"}, {2,"Female"}],
"OptSelected": [{1,"Male"}]},{ "Text": "Favorite color?","Name": "ColorQuestion",
"Options": [{1,"Red"}, {2, "Blue"}, { 3,"Green"}],"OptSelected": [{ 2, "Blue"}] }];
angular.forEach($scope.Questions, function(q) {
var propModel = "Answers['" + q.Name + "']";
$scope[propModel] = q.OptSelected;
})
In my application I am successful at binding data to select but i canot set the user saved value to select.
I have tried to recreate the issue with fiddle without much success but I think it will provide you all better understanding of what I am trying to do
I would recommend binding to just the Questions array and avoid the complexity of trying to bind to the corresponding question in an Answers array. You can always extract what you need from the Questions array either after a selection has been made or all together through some controller level action.
That said, part of your problem is that you don't have a well formed array of objects.
Here's a simplified, working version:
var app = angular.module('myApp', []);
app.controller('QuestionController', function($scope) {
$scope.Questions = [{
Text: "Gender?",
Name: "GenderQuestion",
Options: [{
id: 1,
desc: "Male"
}, {
id: 2,
desc: "Female"
}],
OptSelected: {
id: 1,
desc: "Male"
}
}, {
Text: "Favorite color?",
Name: "ColorQuestion",
Options: [{
id: 1,
desc: "Red"
}, {
id: 2,
desc: "Blue"
}, {
id: 3,
desc: "Green"
}],
OptSelected: {
id: 2,
desc: "Blue"
}
}];
});
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<div ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="question.OptSelected" ng-options="option as option.desc for option in question.Options track by option.id">
</select>
</li>
</ul>
</div>
</html>
I'm trying to conditionally show and hide columns based on the data returned, if the data set contains any objects meeting conditions.
Here is a sample of the data returned from my search results
[
{
"id": "typeahead-241-1091-option-0",
"label": "Android Home Page",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-1",
"label": "Google",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-2",
"label": "Forgotten Google Play Password",
"model": {
"type": "kb",
}
}
]
Now I'm presenting the data in columns, based on the type.
<div class="flexitem">
<h4>External Links</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'link'">{{match.label}}</div>
</div>
<div class="flexitem">
<h4>Knowledge Base</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'kb'">{{match.label}}</div>
</div>
<!-- the below has no results. I want it hidden altogether
currently it shows the <h4>Products</h4> with nothing below it-->
<div class="flexitem">
<h4>Products</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'product'">{{match.label}}</div>
</div>
What I need to accomplish is putting conditions on the flexitem divs altogether to only show if there are results for that type. So if there are no results with the type == 'product', then don't even show that div. A ng-if on that row would work, but what will be the best way to cycle through all of the children of match to determine if there is a result? indexOf doesn't work through children arrays.
Put the logic on the angular side using Array.filter to separate arrays;
Angular controller:
$scope.linkMathches = $scope.matches.filter(function(m){
return m.model.type === 'link'
});
$scope.kbMathches = $scope.matches.filter(function(m){
return m.model.type === 'kb'
});
HTML:
<div class="flexitem" ng-if="linkMathches.length">
<h4>External Links</h4>
<div ng-repeat="match in linkMathches">
{{match.label}}
</div>
</div>
<div class="flexitem" ng-if="kbMathches.length">
<h4>Knowledge Base</h4>
<div ng-repeat="match in kbMathches">
{{match.label}}
</div>
</div>
Going further for dynamic values in model.type:
Angular controller:
$scope.typeMatches = {
link: {title: 'External Links', matches: []},
kb: {title: 'Knowledge Base', matches: []},
product: {title: 'Products', matches: []}
};
$scope.matches.forEach(function(match){
$scope.typeMatches[match.model.type].matches.push(match);
});
HTML:
<div class="flexitem"
ng-if="value.matches.length"
ng-repeat="(key,value) in typeMatches">
<h4>{{value.title}}</h4>
<div ng-repeat="match in value.matches">
{{match.label}}
</div>
</div>
I want to be able to have a list of items and to select one using a checkbox:
<div data-ng-repeat="device in devices">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> {{ device.name }}
</label>
</div>
</div>
</div>
If this can be done using a custom directive that would also be cool!
So the idea, that when a checkbox is checked the device would go into an ng-model and all the other checkboxes would be disabled.
I have a feeling there needs to be a custom model created, something like:
devices = [{
name: "LED",
checked: false,
id: "98"
},{
name: "LED 2",
checked: false,
id: "8"
},{
name: "LED 3",
checked: false,
id: "78"
}]
Just need some function to fire each time one checkbox is checked.
I expect that it can be done with a ng-click on the checkbox? And a two way data binding on the model for canBeChecked
devices = [{
name: "LED",
checked: false,
id: "98",
canBeChecked: true
},{
name: "LED 2",
checked: false,
id: "8",
canBeChecked: true
},{
name: "LED 3",
checked: false,
id: "78",
canBeChecked: true
}]
Iterate over your collection and display a checkbox for each:
<div ng-repeat="device in devices">
<label>
{{ device.name }}
<input type="checkbox" ng-model="device.checked" ng-click="change(device)">
</label>
</div>
Note that the checkbox also has the ng-click directive. This is what you want to trigger each time a checkbox is clicked. The triggered function clears all checkboxes and only checks the clicked one. The checkboxes should now behave like radio buttons.
Your controller might look like this:
app.controller("MyCtrl", ["$scope", function($scope) {
$scope.devices = [{
name: "LED",
checked: false
}, {
name: "LED 2",
checked: false
}, {
name: "LED 3",
checked: false
}];
$scope.change = function(device) {
angular.forEach($scope.devices, function(item) {
item.checked = false;
});
device.checked = true;
};
}]);
It is not necessary to create the canBeChecked property you mention.
Here's the full working example: http://jsfiddle.net/zxdr8/
If you must use checkboxes, here is how you would do it.
Markup:
<div data-ng-repeat="device in devices">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="device.checked" ng-change="checkDevice(device)"> {{ device.name }}
</label>
</div>
</div>
</div>
Controller:
$scope.devices = [{
name: "LED",
checked: false,
id: "98"
},{
name: "LED 2",
checked: false,
id: "8"
},{
name: "LED 3",
checked: false,
id: "78"
}];
$scope.checkDevice = function (device) {
for (var i = 0, len = $scope.devices.length; i < len; ++i) {
if ($scope.devices[i] !== device)
$scope.devices[i].checked = false;
}
});
Your checked and canBeChecked properties seems like merely an UI thing. In my opinion, you should not be creating a custom data models and duplicating unnecessary properties just to do that. Believe me, I did things like that too when started using Angular, but there are much better ways.
Consider storing selected data in other location (model, service, controller, whatever). And maybe if you can store just an ID (primitive property), you can do your "checkbox-radio-like-element" like this:
<div ng-repeat="device in devices">
<label>
<input type="checkbox" ng-true-value="{{device.id}}" ng-false-value="" ng-model="some.storage">
{{device.name}}
</label>
</div>
And thats all you need, no background code needed. When Angular team implements interpolation support for ngTrueValue and ngFalseValue directives, you will be able to store the whole objects and reset model to e.g. null.