split string using angularjs - javascript

I'm trying to split a string pulled from a JSON array in angular. I've tried using the angular {{filter}} but not sure I'm on the right track. I want each tag in it's own link. ie <a ng-href="">tall</a> | <a ng-href="">large</a> etc...
<body ng-app="feedApp">
<div ng-controller="FeedController as feedCtrl">
<ul class="tags">
<li>Tags: </li>
<li>
<a ng-href="http://www.example.com/{{feed.tags|filter:' '}}" ng-repeat="feed in feedCtrl.feeds">{{feed.tags|filter:' '}} | </a>
</li>
</ul>
</div>
</body>
JS
var app = angular.module('feedApp', [ ]);
app.controller('FeedController', ['$http', '$scope',function($http, $scope){
var array = this;
array.feeds = [ ];
$http.get('tags.json').success(function(data){
array.feeds = data;
});
JSON
[
{
"tags": "tall large winner skill"
},
{
"tags": "short knowledge"
},
]
I have a PLUNKER that shows the code above - thanks

I suggest you to manipulate the data read from tags.json producing a simple array with a tag for each element. To do so, you can use simple JavaScript code:
$http.get('tags.json').success(function(data) {
var splittedTags = data.map(function(e) {
return e.tags.split(' ');
});
array.feeds = splittedTags.reduce(function(a, b) {
return a.concat(b);
});
});
First I use Array.prototype.map() to extract from every object inside data the value of tags attribute and split it. This produce an array of array. I use the Array.prototype.reduce() to flatten the array and produce and array with the single tags.
Then, in the HTML page I remove the Angular.js filter and use directly the feed value:
<li>
<a ng-href="http://www.example.com/{{feed}}" ng-repeat="feed in feedCtrl.feeds">{{feed}} | </a>
</li>
Here you can find the PLUNKER with the code.

Here is how you can do it.
First you need to split the string by defining the delimiter (in your case is space). You then assign it to your scope:
var app = angular.module('feedApp', []);
app.controller('FeedController', ['$http', '$scope',function($http, $scope){
var array = this;
array.feeds = [ ];
var strings = [];
$http.get('tags.json').success(function(data){
data.map(function(elem) {
strings.push(elem.tags.split(' '));
});
array.feeds = strings;
});
}]);
If you are done with this in your template you can iterate over your array with ng-repeat recursively:
<body ng-controller="FeedController as feedCtrl">
<ul class="tags">
<li>Tags: </li>
<li>
<div ng-repeat="feeds in feedCtrl.feeds">
<div class="link" ng-repeat="(key, value) in feeds">
<a ng-href="http://www.example.com/{{value}}" >{{value}} | </a>
</div>
</div>
</li>
</ul>
</body>
Here is the working plunkr.

Related

ng-repeat doesnt loop thru my array

Hey everybody can somebody please give me a clue what im doing wrong here?
I trying to build a wrapper where every element in my array gets a and a id
But when i loop thru my real array i only get a error with the text: Error: [ngRepeat:dupes] ...
With a fake array i made it works perfect.
MY HTML:
<div class="translaterBox">
<span ng-repeat="person in persons" id="{{person}}">
{{person + " "}}
</span>
<span ng-repeat="text in textWords" id="{{text}}">
{{text + " "}}
</span>
</div>
MY SCRIPT
var app = angular.module('splitScreenApp', []);
app.controller('splitCtrl', function ($scope, $http) {
$scope.translatetText = "Translate Here";
$http.get("getContent.php")
.then(function (response) {
var content = response.data.content;
$scope.content = content;
function splitContentToWords() {
var text;
for(var i = 0; i <= content.length;i++ ){
if(content[i].text){
var text = content[i].text;
}
return text.split(' ');
}
}
$scope.persons = [
'Jack',
'Jill',
'Tom',
'Harvey'
];
$scope.textWords = splitContentToWords();
console.log($scope.textWords);
console.log($scope.persons);
});
});
Thank you really much for your help
When you get an error about dupes from Angular, it is because there are duplicate keys. You can solve this by using track by as seen in the documentation.
Try changing your ng-repeat to:
<span ng-repeat="person in persons track by $index" id="{{person}}">
<span ng-repeat="text in textWords track by $index" id="{{text}}">

Deleting elements dynamically from ng-repeat generated list

I am having an array of json objects which have nested arrays. I am using ng-repeat to create list with those nested arrays. I want to delete the items from list dynamically on button click. I have written a function in controller to do that-
$scope.remove= function(path){
var obj = $scope.results[$scope.editIndex];
var i;
for(i = 0; i<path.length-1;i++){
var key = path[i].key;
var index = path[i].index;
if(!obj[key]) return;
obj = obj[key]
}
delete obj[path[i].key][path[i].index];
}
and calling it like-
<ul ng-show="showFeatures">
<li ng-repeat="(featureIndex,feature) in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove([{key:'features',index:featureIndex}])">delete</i>
</li>
</ul>
Problem is that I can not delete more than one element, as after first element indexes will change in array, but ng-repeat does not changes index in its scope. How can I solve this problem ? Can I make ng-repeat, re plot itself after I make any changeI am just learning angular js, so please guide me if there is a better way to do such things.
<li ng-repeat="(featureIndex,feature) in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove([{key:'features',index:featureIndex}])">delete</i>
</li>
Here result.features is an array. So send $index from AngularJS template which will correspond to the array index which you want to delete.
e.g., ng-click="remove($index)"
then in controller
function remove(index){
$scope.result.features.splice($index, 1)
}
try this:
<li ng-repeat="feature in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove(feature )">delete</i>
</li>
and in remove function
function remove(feature){
var index = $scope.result.features.indexOf(feature);
if(index > -1)
$scope.result.features.splice(index, 1);
}
var app = angular.module("app", []);
app.controller('mainCtrl', function($scope){
$scope.result = {
features:
[
"ali","reza","amir"
]
};
$scope.remove = function(feature){
var index = $scope.result.features.indexOf(feature);
if(index > -1)
$scope.result.features.splice(index, 1);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet"/>
<div ng-app="app" ng-controller="mainCtrl">
<li ng-repeat="feature in result.features">
<span ng-bind="feature"></span>
<i ng-click="remove(feature)">delete</i>
</li>
</div>

How to convert html tree in to a customized json tree using jquery?

<ul id='parent_of_all'>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='operator'>||</span>
<ul>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='condition'>1 == 1</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<span class='condition'>1 != 0</span>
</li>
</ul>
</li>
</ul>
to
{"&&":[{'||':[ {'&&':[ {"lhs": "1", "comparator": "==", "rhs":"1"} ]} ] } , {"lhs": "1", "comparator": "!=", "rhs":"0"}]}
As of now, I know the basics of jQuery, JavaScript. I need to know where to start thinking in order to accomplish the above conversion.
And the html tree could be more complex with more children.
You can do this with each and map
var obj = {}
var span = $('li > span').not('ul li span').text();
$('ul li span').each(function() {
var text = $(this).text().split(' ');
obj[span] = (obj[span]||[]).concat({lhs: text[0], comparator: text[1], rhs: text[2]});
});
console.log(obj)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>
<span>&&</span>
<ul>
<li>
<span>1 == 1</span>
</li>
</ul>
<ul>
<li>
<span>1 != 0</span>
</li>
</ul>
</li>
You will need a way to select the first level of li, I assumed you have a parent element with an id such as list. I wrote the following code using basic jquery so you can understand it.
var result = {};
var $all_li = $('#list').children('li'); // selecting the first level of li
for(var i in $all_li){ // iterating all_li using for (you may use forEach )
var $current_li = $( $all_li[i] ); // getting operator from first span
var operator = $current_li.children('span').html(); // the text of the operator
var $inner_spans = $current_li.find('>ul >li >span'); // getting list of children spans (from path $list>li>ul>li>span)
var li_spans = []; // an array where we will put the inner span objects
for(var j in $inner_spans){ // iterating the inner spans
var text = $($inner_spans[j]).html().split(" "); // splitting the html
li_spans.push({
lhs: text[0],
comparator: text[1],
rhs: text[2]
}); // adding the splitted html to an object. Note: error if text didn't have 2 white spaces
}
result[operator] = li_spans; // adding the operator key and li_spans value to the result json
}
This code will parse the html and construct the result json, it should work for the html format you provided. Keep in mind that it does not handle errors (such as bad tree format).
simmiar html formats.
Thanks #Alexandru and #Nenad for giving a start. I have been able to complete this on my own.
Below is the function that generates json.
function prepare_json(current_node){
var object = {}
var span = $(current_node).children('span')
if (span.hasClass('condition')){
var text = span.html().split(" ");
object = {lhs: text[0], comparator: text[1], rhs: text[2]}
}
else if(span.hasClass('operator')){
var operator = span.text()
object[operator] = (object[operator] || [])
var children = $(current_node).children('ul').children('li')
for(var i = 0; i < children.length; i++){
var child_pql = prepare_json([children[i]])
object[operator].push(child_pql)
}
}
return object
}
Below is the code that calls that function:
var parent_node = $('#parent_of_all').children('li')
var json = JSON.stringify(prepare_pql_json(parent_node), null, 2)

Add entries from the top in to-do list angular

I have made this to-do list in angular but would like the posts entered to entered fro m the top instead the bottom.
my code:
HTML
<a href="{{url.title}}" class="link">
<p class="title">{{url.name}}</p>
<p class="url">{{url.title}}</p>
</a>
</div>
<div class="col-md-4 delete m-b-2">
<!--a href="javascript:" ng-click="edit($index)" type="button" class="btn btn-primary btn-sm">Edit</a-->
Delete
</div>
</div>
</li>
JS
var urlFire = angular.module("UrlFire", ["firebase"]);
function MainController($scope, $firebase) {
$scope.favUrls = $firebase(new Firebase('https://lllapp.firebaseio.com/'));
$scope.urls = [];
$scope.favUrls.$on('value', function() {
$scope.urls = [];
var mvs = $scope.favUrls.$getIndex();
for (var i = 0; i < mvs.length; i++) {
$scope.urls.push({
name: $scope.favUrls[mvs[i]].name,
title: $scope.favUrls[mvs[i]].title,
key: mvs[i]
});
};
});
You can use unshift() instead of push() when you add elements to your array. It adds the element at the beginning of your array instead of at the end, and since your angular view is based on the model it will add it on top.
Use $scope.urls.splice(index_to_insert,0, object); so in your case you could do
var obj = {
name: $scope.favUrls[mvs[i]].name,
title: $scope.favUrls[mvs[i]].title,
key: mvs[i]
};
$scope.urls.splice(0,0, obj);

Sort/GroupBy files pre-uploaded using AngularJS

I want to group my files before to upload them by extension(The extension can not be defined in the mime type attribute defined by the upload infos. So I used groupBy defined by angular-filter and instead to put an attribute('file.name' for example) to the filter Im using a function to get the extension.
So I want my pre-loaded files appears like this:
Extension1:
file3.Extension1
file1.Extension1
Extension2:
file4.Extension2
file2.Extension2
This is my EXAMPLE
Also my code:
<ul>
<li ng-repeat="f in files | groupBy: fileExtension" style="font:smaller">
{{f.name}}
</li>
</ul>
$scope.fileExtension = function(file) {
return file.name.split('.').pop();
};
Any suggestion is appreciated!
I would transform your list of file names into a list of file groups inside of an ngController or service. Binding to this transformed collection becomes trivial in the view.
$scope.groups = groupByExt(filenames);
function groupByExt(filenames) {
var extensions = [];
var groups = [];
angular.forEach(filenames, function(item) {
var extension = item.substring(item.lastIndexOf(".")+1);
if (!extensions[extension]) {
var group = { name: extension, files: [] };
extensions[extension] = group;
groups.push(group);
group.files.push({ name: item });
}
else {
var group = extensions[extension];
group.files.push({ name: item});
}
});
return groups;
}
HTML
<ul>
<li ng-repeat="group in groups">
{{ group.name }}
<ul>
<li ng-repeat="file in group.files">
{{ file.name }}
</li>
</ul>
</li>
</ul>
Demo
You can also set up $watchers so that when the original filenames list changes, it updates the file groups:
$scope.$watchCollection('filenames', function(newVal, oldVal) {
if(newVal !== oldVal) {
$scope.groups = groupByExt(newVal);
}
});
Demo
I would avoid filters because filters should not change the references of the underlying items (infinite digest issue)

Categories