combine string and html string and display in ui-bootstrap popover - angularjs

I am using restangular to get a collection of items from a server. each item has a description, which is a normal string and a longDescription which contains html describing how it should be formatted.
I am trying to display this information in a single ui-bootstrap popover
I have added a restangule response interceptor like so
var addTrustedDesc = function(room) {
var result;
var desc = room.description;
var longDesc = room.longDescription;
if(desc && longDesc) {
result = desc + ' </br> ' + longDesc;
} else if(desc) {
result = desc;
} else if(longDesc) {
result = longDesc;
}
room.trustedDesc = $sce.trustAsHtml(result);
return room;
};
RestangularConfigurer.addResponseInterceptor(function(data) {
return _.map(data, function(room) {
return addTrustedDesc(room);
});
});
and then much later I try to use the trustedDesc in the popover like so
popover="{{ row.data.trustedDesc }}"
but the popover just displays {}
if I change the line above to
room.trustedDesc = $sce.getTrustedHtml($sce.trustAsHtml(result));
or simply
room.trustedDesc = result;
then the popover displays the full string including the html elements
is it possible to get the popover to render the html and display it?

Your problem is most likely that the bootstrap ui popover cannot handle custom template. I would try to use the custom popover of angular strap instead http://mgcrea.github.io/angular-strap/#popovers

Related

Show data in inputbox from 1 object and save it in using another object

I'm clicking a table row to edit the fields in a modal. The modal must have 2 functionalities (Add or Edit) depending on the GET request data like below.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
}
HTML
<label ng-if="editedObject.email">{{editedObject.email}}</label>
<label ng-if="!editedObject.email">Email</label>
<input ng-model="newObject.email" />
I am able to display the object in the labels, but that's not much help, because the data needs to be shown in the input boxes to be Edited and Saved.
How can i show the data from editedObject.email in the input, so i can save it using newObject.email?
I tried ng-init="editedObject.email", but it doesn't work. Is there some other ng-something that does this or i should be doing it in another way?
Update:
Edit and Update Methods, both are in the mainController.
$scope.editInterview = function(id) {
$http.get('/api/getinterview/' + id).then(function(response) {
editedObject = response.data.item
})
}
//Controller for the Modal
function DialogController($scope, $mdDialog, editedObject) {
$scope.editedObject = editedObject
$scope.submitObject = function(newObject) {
$http.post('/api/interview', newObject)
}
}
You have to make a deep copy from editObject.email to newObject.email. This could be done this way in controller after editOject.email has a value assigned.
$scope.newObject.email = angular.copy($scope.editObject.email);

AngularJS: searching data client side by custom filter

i am learning angular. so i am not good in angular. i am showing data in tabular format with the help of ng-repeat. i have one dropdown and textbox for filter data showing by ng-repeat. fields name are populated in dropdown. so user will select field name and put corresponding value in textbox and search will perform accordingly and data will be shown.
my code is working partially. basically some kind of problem is there in SearchList function. the problem is when trying to search by id then SearchList is not working properly. so looking for help. what to fix in the code. my js fiddle https://jsfiddle.net/tridip/rnoo3bqc/6/
$scope.SearchList = function(row) {
if ($scope.selectedFieldName && $scope.searchText) {
var propVal = row[$scope.selectedFieldName.toLowerCase()];
if (propVal) {
return propVal.toUpperCase().indexOf($scope.searchText.toUpperCase()) > -1;
} else {
return false;
}
}
return true;
};
working version url
https://jsfiddle.net/tridip/rnoo3bqc/8/
You need to convert the id's from number to string, e.g. by concatenating an empty string:
var propVal = row[$scope.selectedFieldName.toLowerCase()] + '';
the problem was with id that's a numeric field and hence toUpperCase() was failing for it.
if (propVal) {
propVal.toString().toUpperCase().indexOf($scope.searchText.toUpperCase()) > -1;
} else {
return false;
}

AngularJS Get text selection and append html to start and end of selection

Have little dilemma here. I'm building text editor in angular js. The problem that I have is, when user selects part of text within a paragraph or heading I need to change styling of that part of text to bold / italic etc.
So basically I need to wrap selected text in <strong></strong> or <em></em>.
Plunker
I have a directive
editorApp.directive('watchSelection', function() {
return function(scope, elem) {
elem.on('mouseup', function() {
scope.startPosition = elem[0].selectionStart;
scope.endPosition = elem[0].selectionEnd;
// scope.selected = elem[0].value.substring(start, end);
scope.$apply();
});
};
});
That gets text selection its startposition and endposition. On button click I need to wrap that selection in specific tags, which I'm hoping to accomplish with this function:
$scope.boldText = function(startPosition, endPosition) {
$scope.start = startPosition;
$scope.end = endPosition;
var htmlStart = angular.element('<strong>');
var htmlEnd = angular.element('</strong>');
$scope.start.append(htmlStart);
$scope.end.append(htmlEnd);
};
I relatively new to angular and I might have taken a bigger bite than I can handle :)
Issue is I can't get selection to wrap inside them tags.
You don't need to watch anything.
$scope.boldText = function() {
document.execCommand('bold');
};
This will bold the selected text.

How can I get ng-click to function with ng-repeat and ng-bind-html?

I am trying to get a ng-click directive to function within an ng-repeat and ng-bind-html. The ng-click code is added to a string of html from data pulled from the server (hence the ng-bind-html). The setup has a controller, a base template that is put onto the page with Drupal, and a partial that is loaded via the template from Drupal.
The controller looks like this at the moment:
var guideListController = angular.module('app')
.controller('guideListController', [
'$scope',
'$sce',
'$compile',
'ViewService',
'ToolKit',
function($scope, $sce, $compile, ViewService, ToolKit) {
// Storage for which rows need more/less links
this.rowIndex = [];
this.showFull = false;
this.showFullClick = function() {
alert('Showfull');
};
this.trustIntro = function(code) {
return $sce.trustAsHtml(code);
};
// Fetch the guide list view from services
var data = ViewService.get({view_endpoint:'guide-service', view_path: 'guide-list'}, function(data) {
//console.log(data);
// Update/process results
for (var row in data.results) {
// Create short intro w/ truncate.js
data.results[row].Intro_short = $sce.trustAsHtml($scope.guideList.getShortIntro(data.results[row], row));
//data.results[row].Intro_short = $scope.guideList.getShortIntro(data.results[row], row);
// Update intro
data.results[row].Introduction = $sce.trustAsHtml($scope.guideList.updateIntro(data.results[row], row));
//data.results[row].Introduction = $scope.guideList.updateIntro(data.results[row], row);
}
$scope.guideList.guides = data.results;
});
// Add a read less anchor tag at the end of the main intro
this.updateIntro = function(row, row_index) {
var intro = row['Introduction'].trim();
if ($scope.guideList.rowIndex[row_index]) { // only apply Less link if needed
var index = intro.length - 1;
var tag = [];
if (intro.charAt(index) === '>') { // we have a tag at the end
index--;
do {
tag.push(intro.charAt(index));
index--;
} while (intro.charAt(index) != '/'); // the closing tag
index--; // we move the index one more for the "<"
tag.reverse(); // Reverse
tag = tag.join('');
}
var inserts = ['div', 'p']; // we insert the Less link here.
if (jQuery.inArray(tag, inserts) >= 0) { // insert into the tag
intro = intro.substr(0, index) + ' <a class="less" ng-click="$parent.guideList.showFull = false">Less</a>' + intro.substr(index);
}
else { // insert at the end of the html
intro = intro + '<a class="less" ng-click="this.showFull = false">Less</a>';
}
}
return intro;
};
// Truncate the long intro into a shorter length blurb
this.getShortIntro = function(row, row_index) {
// Truncate if necc.
var short_intro = jQuery.truncate(row['Introduction'], {
length: 250,
words: true,
ellipsis: '\u2026 <a class="more moreish" attr-ng-click="guideList.showFullClick()">Read on</a>'
});
var more = jQuery('.more', short_intro); // select more link
if (more.length) { // do we have a more link
$scope.guideList.rowIndex[row_index] = true;
}
else { // no more link
$scope.guideList.rowIndex[row_index] = false;
}
$compile(short_intro)($scope);
return short_intro;
};
}]);
As you can see in the ViewService.get() call, data is fetched and then processed. The processing simply involves putting a link at the end of the "Intro" field that is intended to be clickable.
For a while I was having a tough time to even get the ng-click directive to even show (it was being filtered out w/out $sce.trustAsHtml). Now it is there but clicking it has no effect.
The main template (from Drupal) currently looks like:
<div class="guide-listing" ng-controller="guideListController as guideList">
<a ng-click="guideList.showFullClick()">Click me</a>
<div class="guide-teaser"
ng-repeat="guide in guideList.guides"
ng-include src="'/sites/all/themes/ngTheme/ngApp/partials/guide_teaser.html'">
<!-- See guide_teaser.html partial for guide teasers -->
</div>
</div>
The ng-click as placed in the Drupal template above works as expected.
And for the partial that is used in the ng-repeat, it looks like so:
<div ng-controller="guideListController as guideList">
<h2 class="guide-teaser-title">{{guide.node_title}}</h2>
<div class="guide-teaser-intro" ng-bind-html="guide.Introduction" ng-show="guide.showFull">
{{guide.Introduction}}
</div>
<div class="guide-teaser-intro-short" ng-bind-html="guide.Intro_short" ng-show="!guide.showFull">
{{guide.Intro_short}}
</div>
</div>
So far I have only been working on getting the ng-click to work on the short_intro and have had no success so far. Any ideas as to what I am doing wrong would be greatly appreciated!
Ok, So I did get some traction! I used the ngHtmlCompile (http://ngmodules.org/modules/ng-html-compile) directive that was created by https://github.com/francisbouvier (thanks!)
The issue was that the new (dynamic) html wasn't being compiled.
At first it didn't work. I had two issues that prevented it from firing:
A: I stopped using $sce.trustAsHtml. Using this in conjunction with the directive caused the content to disappear!
B: The other issue was one of scope. After I changed the directive such that transclude was set to false it worked just fine!

AngularMaterial md-chips : Dont show selected item in <md-autocomplete>

I'm trying the <md-autocomplete> example from here md-chips
To prevent the selected items from coming inside <md-autocomplete> I've modified the querySearch function like this:
function querySearch (query) {
var results = query ? self.searchData.filter(createFilterFor(query)) : [];
var finalResults = [];
angular.forEach(results, function(result) {
if($scope.selectedItems.indexOf(result.name) < 0) {
finalResults.push(result);
updateSelectedItems(result);
}
});
return finalResults;
}
But my problem is that the control does not come inside this function once we select an item. Can someone please explain how to solve this ?
I found the solution from this documentation: md-autocomplete
We just need to add md-no-cache="true" for calling the querySearchfunction each time we search for a query item
The solution that worked for me:
The md-no-cache="true" on md-autocomplete still is a must to force the autocomplete to reinitialize the md-items;
Md-chips should have md-on-remove and md-on-append set and implemented as to remove a chip from the list, or add a chip to the list;
My code looks something like this:
HTML:
md-on-remove="removeTagChip($chip)"
md-on-append="appendTagChip($chip)"
JS:
$scope.removeTagChip = function (chip) {
var chipPos = $scope.getPosition(chip.Id, $scope.ChipTags);
if (chipPos < 0) {
$scope.ChipTags.push(chip);
}
};
$scope.appendTagChip = function (chip) {
var chipPos = $scope.getPosition(chip.Id, $scope.ChipTags);
if (chipPos > -1) {
$scope.ChipTags.splice(chipPos, 1);
}
return chip;
};
$scope.getPosition just returns the position of the chip in the list of chips;

Resources