I am using kendo ui richtextbox on one of my pages:
<textarea kendo-editor rows="3" cols="4" ng-model="fooData.Answer" id="answerInput" placeholder="blablablabla" class="form-control" k-encoded="false"></textarea>
In my controller I have:
function ($scope, $sce, Foo) {
$scope.foos = [];
$scope.fooData = kendo.observable();
$scope.addFoo = function (fooData) {
Foo.create(fooData)
.success(function (data) {
$scope.fooData = kendo.observable();
$scope.foos.push(data);
});
}
Which adds an item foo to a collection using an api, which all works like a charm. The thing that does not work is that the kendo-editor does not get emptied. The input remains. In the documentation they stated that you should use kendo.observables, which I do, but to no avail.
Any ideas?
Apparetnly I just needed to do
$scope.fooData.Answer = "";
$scope.fooData.Question = "";
in my addFoo function.
Related
I have the following controller
angular.module('publicApp')
.controller('URLSummaryCtrl', function ($scope, $location, Article, $rootScope, $timeout) {
$scope._url = "";
$scope._title = "";
$scope._article = "";
$scope._authors = "";
$scope._highlights = [];
$scope._docType = "";
$scope.summarizeURL = function(){
Article.getArticleInfo($scope.url, "").then(
function(data){
$scope._url = data.url;
$scope._title = data.title;
$scope._authors = data.authors.join(', ');
$scope._highlights = data.highlights;
$scope._docType = data.documentType;
if($scope._docType == 'html'){
$scope._article = data.article[0].article;
}
else{
$scope._article = data.article;
}
var _highlights = [];
$scope._highlights.forEach(function (obj) {
_highlights.push(obj.sentence);
});
// wait for article text to render, then highlight
$timeout(function () {
$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });
}, 200);
}
);
}
and the following view
<form role="form" ng-submit="summarizeURL()">
<div class="form-group">
<input id="url" ng-model="url" class="form-control" placeholder="Enter URL" required>
</div>
<button class="btn btn-success" type="submit">Summarize</button>
</form>
<div class="col-lg-8">
<h2>{{ _title }}</h2>
<p> <b>Source: </b> {{_url}}</p>
<p> <b>Author: </b> {{_authors}} </p>
<p> <b>Article: </b><p id="article">{{_article}}</p></p>
</div>
When I give a url in the text field initially and click Summarize it works as expected. But when I change the value in the text field and click the button again every thing is updated properly, with the new values, but the $scope._article gets the new value and doesn't remove the old value. It displays both the new and the old value that was there before.
Why is this happening?
EDIT #1: I added more code that I had. I found that when I remove the $timeout(function(){...}) part it works as expected. So now the question is, why is $scope._article keeping the old value and pre-pending the new value?
EDIT #2: I found that $timeout(...) is not the problem. If I change
$timeout(function () {
$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });
}, 200);
to
$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });
it still behaves the same way. So now I'm assuming it's because I'm changing the $scope._article to be something else? What's happening is that I'm displaying the $scope._article value and then modifying what's displayed to contain highlights <em class='highlighed'> ... </em> on what ever I want to highlight.
EDIT #3: I tried to remove the added html before making the request to get new data but that doesn't work either. Here's the code I tried.
angular.module('publicApp')
.controller('URLSummaryCtrl', function ($scope, $location, Article, $rootScope, $timeout) {
$scope._url = "";
$scope._title = "";
$scope._article = "";
$scope._authors = "";
$scope._highlights = [];
$scope._docType = "";
$scope.summarizeURL = function(){
//Remove added html before making call to get new data
$('.highlighted').contents().unwrap();
Article.getArticleInfo($scope.url, "").then(
function(data){ ... }
);
Jquery in angular controllers = headache.
The problem is probably here for you
$timeout(function () {
$('#article').highlight(_highlights, { element: 'em', className: }, 200);
#article.html() here, is going to give weird output, because angular has it's own sync system and the jquery library you're using has it's own way of working with the DOM. Throw in the fact that asynchronous javascript is already a pain if you're working with multiple things.
What you want instead is to set the html to the angular scope variable before you work with it in jquery so you know what the jquery is working with, i.e.:
$timeout(function () {
$('#article').html($scope._article);
$('#article').highlight(_highlights, { element: 'em', className: }, 200);
Within an ng-repeat block I have textboxes. To detect when the content differs from the original, the original data is stored in a variable.
<tr data-ng-repeat="p in products">
<td>
<textarea data-elastic data-ng-model="p.comment" data-ng-change="hasChanged=checkChange(original, rnd.comment);" data-ng-init="original=rnd.comment; hasChanged=false"></textarea>
</td>
<td class="save" ng-show="hasChanged" ng-click="save(p, original)">Save</td>
A save button is shown only when the content has changed. After a successful save the original value should be updated to the new value.
I can do it like this with a function in the controller:
$scope.save = function (p, original) {
//...successful save
this.original = p.comment; //this works
original = p.comment; //this does not
}
Relying on some implicit scope in the form of 'this' doesn't seem sensible.
Why doesn't updating the variable (original = ...) work? What's a smarter way to do this?
Based on comments I've updated it as follows:
ng-click="save(p, this)"
$scope.save = function (p, scope) {
//...successful save
scope.original = p.comment; //this works
}
This seems failrly sensible now. Is passing scope around like this considered bad practice or acceptable?
Products is defined as follows:
productStatusApp.controller('productStatusCtrl', function ($scope, $http, cid) {
$http.get('api/company/products/' + cid).success(function (data) {
$scope.products = data.products;
});
I've found the best way to avoid this kind of problems, is to use services
https://docs.angularjs.org/guide/services
http://viralpatel.net/blogs/angularjs-service-factory-tutorial/
some rough code(use it just for pointers, not tested at all)
<tr data-ng-repeat="p in ProductsService.products">
<td>
<textarea data-elastic data-ng-model="p.comment"></textarea>
</td>
<td class="save" ng-show="p.originalComment!==p.comment" ng-click="ProductsService.save(p)">Save</td>
</tr>
and
var module = angular.module('app', []);
module.service('ProductsService', function () {
var products = [postA,postB,...,PostC];
products = products.map(function(p){p.originalComment=p.comment});
var save = function(p){
p.originalComment=p.comment;
someAjaxRequest(function _callback(err,response){....})
}
return {products:products,save:save};
});
and
module.controller('ProductsController', function ($scope, ProductsService) {
$scope.ProductsService= ProductsService;
});
They also allow better readability , WIN WIN
With the angular-bootstrap-duallistbox component, documented here, and using the $http service, How do I set the selected elements on it?
Here is the used code:
HTML:
<select ng-options="obj as obj.name for obj in authorizations"
multiple
ng-model="selections"
bs-duallistbox
></select>
Javascript:
angular.module('demoApp', ['frapontillo.bootstrap-duallistbox'])
.controller('ProfileAutAsigController',
function ($scope, $http, Authorization) {
$scope.authorizations = [];
$scope.selections = [];
Authorization.query().$promise.then(function (response) {
$scope.authorizations = response;
return $http.get("api/profileAut/1/authorizations");
}).then(function (payload) {
//This doesn't set the selected items. Specifying an
//array manually doesn't work either.
//$scope.selections = [{id:1, name:'Text'},{id:3, name:'Photos'}];
$scope.selections = payload.data;
}, function (payload) {
//Error happened
console.log(payload.error);
});
});
Thanks.
To populate angular bootstrap dual list box you should use track by instead of as like this:
You have to use track by instead as in ng-options
Instead this:
<select ng-model="selected" ng-options="av as av.name for av in available" multiple bs-duallistbox></select>
Uses:
<select ng-model="selected" ng-options="av.name for av in available track by av.id" multiple bs-duallistbox></select>
At last I couldn't make work angular-bootstrap-duallistbox with $http service. I used instead this angular directive, which worked with $http:
https://github.com/alexklibisz/angular-dual-multiselect-directive
Be sure of following the items json format. Read the example.
Here is the plunkr i have created.
Basically i am facing 2 issues with this piece of code -
I need help loading months in the drop down and
When month is changed in the dropdown from headerController, the sales for that month is displayed in detailController. I am trying to create a dependency between multiple controllers using a service.
I will appreciate any help fixing these 2 issues.
You can use $broadcast service for event purposes. Following is the link which explains the use of $broadcast and communicating between two controllers.
enter code herehttp://plnkr.co/edit/d98mOuVvFMr1YtgRr9hq?p=preview
You could simply achieve this by using $broadcast from one controller in $rootScope and listen that event in $scope using $on. Though I would suggest you to use service that will share data among to controller. Using dot rule will reduce your code. Take a look at below optimized code. Also you could replace your select with ng-repeat with ng-option to save object on select.
Markup
<div data-ng-controller="headerController">
<h3>Select Month</h3>
<select id="month" ng-model="sales.selectedMonth"
ng-options="month.monthId for month in sales.monthlySales">
</select>
</div>
<div data-ng-controller="detailsController">
<h3>Sales for Month</h3>
<div ng-bind="sales.selectedMonth"></div>
</div>
Code
app.service('valuesService', [function() {
var factory = {};
factory.sales = {}
factory.sales.salesForMonthId = 10;
factory.sales.months = [1, 2];
factory.sales.monthlySales = [{monthId: 1,sales: 10}, {monthId: 2,sales: 20}];
factory.sales.selectedMonth = factory.sales.monthlySales[0];
return factory;
}]);
app.controller('headerController', ['$scope', 'valuesService',
function($scope, valuesService) {
$scope.sales = {};
getData();
function getData() {
$scope.sales = valuesService.sales;
}
}
]);
app.controller('detailsController', ['$scope', 'valuesService',
function($scope, valuesService) {
$scope.sales = {};
getData();
function getData() {
$scope.sales = valuesService.sales;
}
}
]);
Demo Plunkr
I can see the months are already loading fine.
For proper data binding to work across service and controller, you would need to bind one level above the actual data, resulting a dot in your expression. This is because javascript doesn't pass by reference for primitive type.
In service:
factory.data = {
salesForMonthId: 0
}
In controller:
app.controller('detailsController', ['$scope', 'valuesService',
function ($scope, valuesService) {
$scope.values = valuesService.data;
}
]);
In template:
<div>{{values.salesForMonthId}}</div>
Plunker
I'm trying to take the first example from the angular.js homepage and adding in cookie support.
This is what I have so far: https://jsfiddle.net/y7dxa6n8/8/
It is:
<div ng-app="myApp">
<div ng-controller="MyController as mc">
<label>Name:</label>
<input type="text" ng-model="mc.user" placeholder="Enter a name here">
<hr>
<h1>Hello {{mc.user}}!</h1>
</div>
</div>
var myApp = angular.module('myApp', ['ngCookies']);
myApp.controller('MyController', [function($cookies) {
this.getCookieValue = function () {
$cookies.put('user', this.user);
return $cookies.get('user');
}
this.user = this.getCookieValue();
}]);
But it's not working, ive been trying to learn angular.
Thanks
I'd suggest you create a service as such in the app module:
app.service('shareDataService', ['$cookieStore', function ($cookieStore) {
var _setAppData = function (key, data) { //userId, userName) {
$cookieStore.put(key, data);
};
var _getAppData = function (key) {
var appData = $cookieStore.get(key);
return appData;
};
return {
setAppData: _setAppData,
getAppData: _getAppData
};
}]);
Inject the shareDataService in the controller to set and get cookie value
as:
//set
var userData = { 'userId': $scope.userId, 'userName': $scope.userName };
shareDataService.setAppData('userData', userData);
//get
var sharedUserData = shareDataService.getAppData('userData');
$scope.userId = sharedUserData.userId;
$scope.userName = sharedUserData.userName;
Working Fiddle: https://jsfiddle.net/y7dxa6n8/10/
I have used the cookie service between two controllers. Fill out the text box to see how it gets utilized.
ok, examined your code once again, and here is your answer
https://jsfiddle.net/wz3kgak3/
problem - wrong syntax: notice definition of controller, not using [] as second parameter
If you are using [] in controller, you must use it this way:
myApp.controller('MyController', ['$cookies', function($cookies) {
....
}]);
this "long" format is javascript uglyfier safe, when param $cookies will become a or b or so, and will be inaccessible as $cookies, so you are telling that controller: "first parameter in my function is cookies
problem: you are using angular 1.3.x, there is no method PUT or GET in $cookies, that methods are avalaible only in angular 1.4+, so you need to use it old way: $cookies.user = 'something'; and getter: var something = $cookies.user;
problem - you are not storing that cookie value, model is updated, but cookie is not automatically binded, so use $watch for watching changes in user and store it:
$watch('user', function(newValue) {
$cookies.user = newValues;
});
or do it via some event (click, submit or i dont know where)
EDIT: full working example with $scope
https://jsfiddle.net/mwcxv820/