angular variable initialization - javascript

I have a variable in angular controller, $scope.abc.
I have Sails as backend.
$scope.abc's initial value can be determined by backend when generating the page. After the page is displayed to user, $scope.abc may or may not be changed by the user.
I can have backend to generate a complete static page and let angular query the backend for initial value of $scope.abc. I feel it is not necessary as the initial value can be determined at the page's generation and should come as part of the page.
The question is: how to initialize $scope.abc when the webpage is being generated? Is there any way to provide data to angular js file, similar to res.view("",data)?

You don't really have many options here. You can issue one more ajax request and load data. However it my be not ideal if during index page loading the data is already available. In this case you can inject it into additional script tag and access it from from there.
<script>
// Make sure data is JSON encoded.
window.appConfig = <%= data %>;
</script>
<script src="angular.js"></script>
<script src="app.js"></script>
And then I would set a constant service in the app to store data in it:
angular.module('app').constant('appConfig', {data: window.appConfig});
This way you could use it later in more Angular way, for example:
angular.module('app').controller(function($scope, appConfig) {
$scope.config = appConfig.data.userId;
});
And if you are concerned with presence of the global variable appConfig, you can remove it in app run block, when constant is already set.

Related

how to redirect url in flask depending on a variable

I want to redirect the URL when the variable search_done is true, but until then I want the loading file to show but i can't manage to do so.
I've tried doing all sorts of variable passing to html but because the variable changes during the run of the loading file the variable won't be true.
The URL changes to the loading file when a search button is clicked.
#app.route("/", methods=['GET','POST'])
def index():
global search_done
global songs
if request.method == 'POST':
search_request = request.form.getlist('search[]')
songs=[]
data=search_api(search_request)
search_done=False
if data!=None:
for hit in data:
songs.append(Song(hit['result']['full_title'],hit['result']['primary_artist']['name'],hit['result']['url'],hit['result']['song_art_image_thumbnail_url']))
for i in songs:
print(i)
search_done=True
return render_template('layout.html')
#app.route("/result")
def result():
global songs
return render_template("result.html",songs=songs)
#app.route("/loading")
def load():
global search_done
while not search_done:
return render_template("loading.html")
return redirect(url_for('result'))
I want the url to redirect to 'result' but it just stays as the loading page
It's not possible to do this in the way you're thinking. In short, the most simple way to get there is by adding some Javascript to the page (ajax), and poll your server to find when the variable changes. There are a few things to consider:
How will you store the variable? Session is an option for non-important, small values. Otherwise a DB may be necessary for large data sets, or a background worker may be necessary for long running processes.
Getting the value back into the view can be done using ajax (e.g. jquery $.get) and a setTimeout function with javascript. This should call a new route in your app that retrieves the value from the storage method you're using.
Going fully async and looking at Sockets (for example) will give you the ability to create more 'live' views, where your app view can listen for events and update without reloading. This does change how your app is run however.
Hope this helps!

Using AngularJS to process custom localStorage data

I wrote a bookmarklet that retrieves information from a page and stores it in JSON format in local storage (converting it to a string first, of course).
I would like a web app I am writing to be able to process this data, on the fly, preferably as it gets saved to the localStorage.
Right now i can change the item in LS via the console and refresh the page and the new data appears but I would like it to be live and seamless.
Any advice on how to go about this? I found several localStorage modules for angularJS and I tried them but they don't seem to allow me to retrieve from LS if the data is already there in LS.
In response to answer:
$scope.$watch(
function(){
return $window.localStorage.getItem('TestData');
},
function(newValueInStorage){
$scope.testingLS = newValueInStorage;
}
)
I tried this and I still get the data displayed by just doing a {{ testingLS }} in the view template but when I go and change the TestData key in local storage via the console it doesn't update instantly. (for now, I am just testing it without the bookmarklet with just a simple string inside TestData
There is few ways to do it
One of will be to populate correct model on scope when saving to localStorage
The other that I can think of at this moment is to setup watcher
$watch(
function(){
return localstorage object
},
function(newValueInStorage){
$scope.modelFromLS = JSON.parse(newValueInsStorage)
}
)
---edit---
as per James comment you need something that will handle the fact that data has changed in different tab and $digest process need to run for watch to be recalculated
http://plnkr.co/edit/zlS3wL65meBeA8KkV5KH?p=preview
window.addEventListener('focus', function(){
console.log('focus')
$scope.$digest()
})

Triggering updates / refreshes from outside of AngularJS

I have a web worker whose job it is to periodically poll a webservice for data, and then insert that data into an IndexedDB database.
Is there any recommended way of notifying an AngularJS module of updates to the object stores, since all the changes happen outside of Angular?
Call $scope.$apply() when your web worker finishes. You will want to grab the "root" element of where you bootstrapped your ng-app. For example:
HTML:
<div id="rootElement" ng-app="myApp">
...
</div>
JavaScript:
//Call $apply() to start an angular digest cycle where any updates you made to objects
//angular knows about will update the view.
angular.element(document.getElementById("rootElement")).scope().$apply();
Edit: Including sample onmessage subscribe.
Since your worker is only writing to the IndexedDb, you will need to also use postMessage to get that data back to your HTML (and angular). For example, in your HTML:
var worker = new Worker("pathToWorker.js");
//Start worker in some way
worker.postMessage();
//Use data from the worker to update scope.
worker.addEventListener("message", function (e) {
//Get the data from the worker
var indexData = e.data;
//Update a scope variable (scopevar)
//Note: The element you query with angular.element must have the scope variable you
//are interested in.
angular.element(document.getElementById("MainController")).scope().$apply('scopevar=' + JSON.stringify(indexData));
}, false);
From your worker:
self.addEventListener("message", function (e) {
//Do work to write to IndexedDb
//PostMessage using the indexDb Data so angular can know about it.
self.postMessage({title: "Foo", data: "Bar"});
}
Without seeing your code, I can't give a more specific example, but postMessage from the worker is definitely the way to get data from your worker back to angular.

Conditional Binding with knockout.js/mapping plugin/koExternal template engine /json from ajax

I made a solution for a single page application, which will be used for a Large Screen display in a factory building, displaying status information and performance indicators for a set of machines. Via a settingsfile, which is derived via an ajax call the application knows which machines with which information should be displayed. So for every machine a template, and for each machine information a nested template is rendered(koExternaltemplateengine). Also the first ajax call contains the urls for the ajax calls for all machines. The respondes of these calls contain the machine-specific values. These calls are repeated periodically and the display values are refreshed. All bindings are made with knockout and the mapping plugin to avoid having a hardcoded viewmodel clientside. The frame and the machine containers(panes) are bound to the data from the first call, the nested templates data-fields are bound to data attributes contained in the machine specific ajax calls response.
Now my problem: If all ajax-calls for all machines deliver the required data for the display, everything works fine. BUT: For some machines, at sometimes(also on initial load), the calls are successfull (200) but contain just null (cause at this moment the data is not available).
Now I got the problem. After ko.applybindings(machinedata, machinediv) I got the ' Unable to parse bindings.' for the bound value fields and ko terminates binding. So the display is not rendered complete and no updates are triggered.
Now I will try something with the if/ifnot-bindings, but what happens if after a refresh the initial not bound values are present? (manually retrigger applybindings, additional to ko.mapping.fromJS??).
Did somebody have a similar problem? Any suggestions? As I mentioned I want to avoid hardcoded viewmodels to facilitate future extensions for more machine attributes.
You could store your machinedata in an observable:
Your view:
<div data-bind="if: machinedata()>
<div data-bind="with: machinedata()">
...
</div>
</div>
<div data-bind="if: machinedata()>
Data could not be loaded....
</div>
The view model:
var ViewModel = function () {
var self = this;
self.machinedata = ko.observable();
self.update = function () {
var data = someAjaxCall(); // returns the data or any falsy value
self.machinedata(data);
};
}
var viewModel = new ViewModel();
ko.applyBinding(viewModel); // data does not yet exist
viewModel.update();
As long as you only bound the loaded data and did not need any computeds you even would not need ko.mapping.

AngularJS and embedded framework html

I'm developing a user preferences page and I've decided to use AngularJS to control the state of the data.
What I would like to achieve is a page that shows the current user's settings and allows a user to edit them, cancel their changes, or save & submit changes if they so desire. I've binded my labels and my input controls to the model so that when a user modifies their email address, it is reflected across correctly.
I'm basing my work off this example #3 by the way: http://code.angularjs.org/1.0.0rc12/docs-1.0.0rc12/guide/forms
My question is related to the default values for the page. Since the model is defined as an object in Javascript. In the link above, default values can be set over here in $scope.master= {}; which works fine except that I'm using a framework to generate a static page and not retrieving an json object from my server. My pages are all written in embedded scala, so I access the values serverside. What is the best way to take the info retrieved serverside and turn into an object client side javascript can access?
You have a few choices. The way I would do it would be to push the initial state (through a WebSocket or something) to Angular as JSON, or have Angular pull it from the server through an HTTP call.
You could also perhaps render the page with ng-init tags to set the initial state, but this way seems weird to me.
<div ng-controller="FormController" ng-init="formData = {}">
<form>
<input ng-model="formData.input1" ng-init="formData.input1 = 'initialValue'>
</form>
</div>
I am using ASP.NET and Dapper-Dot-Net. I use the following techniques to get my data on to the page and then into Angular scope. It should be pretty transferable to your environment.
Define a DataTransferObject class in the page on the server side and a public string called DtoJson to hold the serialized version of your class instance.
private class DataTransferObject{
public User User;
public List<Project> Projects
}
public string DtoJson;
var dto=new DataTransferObject();
var userName="however you get a username";
dto.User=User.Get(userName); // I already have a User class
var sql="select * from projects where user_name=:UserName";
var p=new DynamicParameters();
p.Add(":UserId", dto.User.ID);
dto.Projects=Project.Query<Project>(sql, p); // returns a list of Project
// I use json.net to convert the Dto to json and expose it as a public variable
var DtoJson=Json.Convert(dto); // approximate syntax but you get the idea
On the client side I put a script tag at the head of the page and inject the DtoJson into it to get it into the global scope
<script>var dto=<%=DtoJson%>;</script>
At the bottom of my page I have a script src="pageName.js" which is my Angular controller file. Inside the controller I say
$scope.dto=dto;
console.log($scope.dto);
Now the json that was created on the server side is in my controller's scope and I can data bind to {{dto.User.FIRST_NAME}} and {{dto.Projects[0].ID}} ng-repeat="for p in dto.Projects" etc
I hope that that makes sense.
Peter

Categories

Resources