go to post Eduard Lebedyuk · Feb 5, 2017 jQuery is a library - a big collection of "classes" and methods you can use anywhere. It makes no assumptions about how your application is built, has no internal DOM tree representation, etc.Angular JS is an MVC framework - it forces your application to be structured in a very specific way, it manipulates DOM tree of the page according to specified rules. And well, it also provides a big collection of "classes" and methods you can use in your the code, but only the in parts you wrote in compliance with Angular architecture (scopes/controllers/services).
go to post Eduard Lebedyuk · Feb 4, 2017 Please consider removing or at the very least modifying the description of: intersystems-ru~REST 0.8.0-a Basic classes for REST web API on InterSystems Cache It was only relevant with 2014-2015 REST and does not represent best practices for REST APIs in 2016.1+.
go to post Eduard Lebedyuk · Feb 4, 2017 There are some problems with many namespace. I found that after I hit about a hundred namespaces on an instance it's time to purge. 50 seems to be the upper limit of easily manageable for me tbh. More, and scrolling in Studio/SMP takes too much time.
go to post Eduard Lebedyuk · Feb 4, 2017 Do you have a call to CreateBusinessService somewhere in your code? It allows doing business service calls from non-Ensebble context (by well making current job Ensemble job). It's called like this (from Demo.ZenService.Zen.WeatherReportForm): Set tSC=##class(Ens.Director).CreateBusinessService("Zen Service",.tService) Where first arguments is a host name of a business service. In your case the error appeared because the first argument is equal to EnsLib.SOAP.GenericService which is not present in currently running Ensemble production. You need to do one of the: Check that you're running a correct productionChange first argument of CreateBusinessService method from EnsLib.SOAP.GenericService to something that exists in current productionCreate business service in production with the name EnsLib.SOAP.GenericService
go to post Eduard Lebedyuk · Feb 4, 2017 I'd like to add some commentary to Angular 1/2 comparison.Angular 1:- easier to hook to cache (can be used by calling the library from a csp and calling services cache rest)That's same as with Angular 2.- flatter learning curve if jquery is already known- being so similar to jquery jQuery has little in common with Angular. Angular (1 or 2) is an MVC framework and jQuery is the utilities library.- not needed for really small projectsYes, for both Angular 1 and 2.- easier to maintain, perhaps, for someone who knows web, html and jqueryHighly debatable. Learning curve for Angular 1 is fairly steep.Angular 2.- does not work in browsers older than IE9Angular 1 also does not work in browsers older than IE9- keeps changing, it is not completely stable yet?It has a stable version for a few months already. Now, with that said, I'd like to recommend Angular 2. The main advantage in my opinion is that many fundamental problems present in Angular 1 were solved in Angular 2. Here's some links elaborating on differences between Angular 1 and 2:Short comparison of differences between Angular 1 and 2 is available here.More detailed comparison is available here.
go to post Eduard Lebedyuk · Feb 2, 2017 That is almost what I started this topic with. I get a compilation error with this code. And fields data_Year and data_Month are not getting created it seems.
go to post Eduard Lebedyuk · Feb 2, 2017 Thank you!I copied your example, but SQL returns results saved on disk, which is expected as the data property is triggered computed Class CS.Persistent Extends %Persistent { Property data As CS.Serial [ SqlComputeCode = {set {*} = ##class(CS.Persistent).dataGetStatic()}, SqlComputed ]; /// data getter method in SQL context ClassMethod dataGetStatic() As %List { quit $lb(2017,1) } /// do ##class(CS.Persistent).test() ClassMethod test() { do ..%KillExtent() do $system.SQL.PurgeForTable($classname()) set obj = ##class(CS.Persistent).%New() set obj.data.Month=-1 set obj.data.Year=0 set sc = obj.%Save() write !,"Save: ",$s($$$ISOK(sc):"OK", 1:$System.Status.GetErrorText(sc)),! zw ^CS.PersistentD do ##class(%SQL.Statement).%ExecDirect(,"select * from "_$classname()).%Display() } } I execute in a terminal: do ##class(CS.Persistent).test() And I receive the following output: Save: OK ^CS.PersistentD=1 ^CS.PersistentD(1)=$lb("",$lb(0,-1)) ID data_Month data_Year 1 -1 0 Can I make a serial class always computed? I want to receive the following output: Save: OK ^CS.PersistentD=1 ^CS.PersistentD(1)=$lb("",$lb(0,-1)) ID data_Month data_Year 1 1 2017
go to post Eduard Lebedyuk · Jan 27, 2017 There should not be a problem with underscores: set obj = ##class(%DynamicObject).%FromJSON("{""a_b"":1}") w obj."a_b" >1
go to post Eduard Lebedyuk · Jan 25, 2017 Macros can eliminate using $method/dynamic dispatch here altogether.
go to post Eduard Lebedyuk · Jan 25, 2017 Macros for method names which compile into AmethodName or methodName depending on global var set for compilation then. Dynamic dispatch is a hit on speed anyway.
go to post Eduard Lebedyuk · Jan 25, 2017 Always call do a.AmethodName() And inside dynamic dispatch check global variable %debug (or global, or some IsDebug method etc.). If it exists call both annotation methods and target method, If it does not exist only call target method.
go to post Eduard Lebedyuk · Jan 25, 2017 Another approach would be using dynamic dispatch: Let's say you have this method: /// @NiceTest1 ClassMethod Test() { Write 1 } Using Class Generators you generate 2 additional methods: /// @NiceTest1 ClassMethod OnBeforeTest() { Write "Before NiceTest1" } /// @NiceTest1 ClassMethod OnAfterTest() { Write "After NiceTest1" } and you add dynamic dispatch method (and dynamic dispatch classmethod) to the class: /// Is used to implement an unknown method call. It is also used /// to resolve an unknown multidimensional property reference (to get the value /// of a property) because that syntax is identical to a method call. Method %DispatchMethod(Method As %String, Args...) [ ServerOnly = 1 ] { // Amethod -> method set Method = $e(Method, 2, *) do $method(, "OnBefore" _ Method, Args...) do $method(, Method, Args...) do $method(,"OnAfter" _ Method,Args...) } So, as a whole it can look like this: Class Utils.Annotations1 Extends %RegisteredObject { Method OnBeforeTest() { Write "Init NiceTest1",! } /// @NiceTest1 Method Test() { Write 1,! } Method OnAfterTest() { Write "End NiceTest1",! } /// Is used to implement an unknown method call. Method %DispatchMethod(Method As %String, Args...) [ ServerOnly = 1 ] { set Method = ..getMethodName(Method) do $method(, "OnBefore" _ Method, Args...) do $method(, Method, Args...) do $method(,"OnAfter" _ Method,Args...) } /// Is used to implement an unknown class method call ClassMethod %DispatchClassMethod(Class As %String, Method As %String, Args...) [ ServerOnly = 1 ] { set Method = ..getMethodName(Method) do $classmethod(, "OnBefore" _ Method, Args...) do $classmethod(, Method, Args...) do $classmethod(,"OnAfter" _ Method,Args...) } ClassMethod getMethodName(method As %String) As %String { // Amethod -> method set method = $e(method, 2, *) return method } } Works like this: USER>do a.ATest() Init NiceTest1 1 End NiceTest1 USER>do a.Test() 1
go to post Eduard Lebedyuk · Jan 24, 2017 You can modify method code during compilation (obviously dangerous) using generators. Here's the sample that annotates all methods, containing @ in description: Class Utils.Annotations { /// @NiceTest1 ClassMethod Test() { Write 1 } ClassMethod OnCompile() As %Status [ CodeMode = objectgenerator ] { #dim sc As %Status = $$$OK for i=1:1:%class.Methods.Count() { #dim method As %Dictionary.MethodDefinition = %class.Methods.GetAt(i) if method.Description [ "@" { set sc = ..annotate(method) quit:$$$ISERR(sc) } } quit:$$$ISERR(sc) sc set sc = %class.%Save() quit sc } ClassMethod annotate(method As %Dictionary.MethodDefinition) As %Status { #dim sc As %Status = $$$OK set code = method.Implementation.Read($$$MaxCacheInt) set code = ..cleadOldAnnotation(code) set code = ..addNewAnnotation(code, $e(method.Description, 2,*)) do method.Implementation.Clear() do method.Implementation.Write(code) quit sc } ClassMethod cleadOldAnnotation(code As %String) As %String { if $find(code, "//init annotation end") { set code = $e(code, $find(code, "//init annotation end") + 2, $find(code, "//complete annotation start") - $l("//complete annotation start") - 2) } return code } ClassMethod addNewAnnotation(code As %String, annotation As %String) As %String { #define Tab $c(9) set code = $$$Tab _ "Write ""Init " _ annotation _ """" _ $$$NL _ $$$Tab _ "//init annotation end" _ $$$NL _ code _ $$$Tab _ "//complete annotation start"_ $$$NL _ $$$Tab _ "Write ""End " _ annotation _ """" return code } } Compiles into: /// @NiceTest1 ClassMethod Test() { Write "Init NiceTest1" //init annotation end Write 1 //complete annotation start Write "End NiceTest1" } GitHub
go to post Eduard Lebedyuk · Jan 20, 2017 Yes, you can query everything you see in Message Viewer and Event Viewer. Their code is defined in EnsPortal.MessageViewer.zen and EnsPortal.EventLog.zen respectively. You can see the queries these pages use and adapt them, or inherit from them and publish it as another separate web application.Also, here's modification example - Ensemble Log Viewer with namespace support.